[codex] clarify KBR ChatGPT import instructions#291
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces support for uploading and processing multiple Leistung files simultaneously, ensuring each file's correction data is kept isolated. It also defines JSON output structures for Zwischenexport and Ende Korrektur containing the contract JSON. The reviewer identified a critical issue where inlining the full contract JSON multiple times within the prompt examples will cause massive token bloat. They suggest using a placeholder <contract_json_object> in the examples and defining a single Contract JSON section at the bottom of the prompt, along with updating the corresponding test assertions.
| JSON structure to output for \`Zwischenexport\`: | ||
| { | ||
| "contract": {{contractJson}}, | ||
| "chatRef": "chat-0001", | ||
| "importedTaskScores": [ | ||
| { | ||
| "taskId": "task-1", | ||
| "points": 0, | ||
| "maxPoints": 0, | ||
| "scoringUnitId": "task-1.score", | ||
| "comment": "Kurzbegruendung mit Bezug zur Leistung", | ||
| "confidence": 0.8, | ||
| "evidenceIds": ["evidence-1"] | ||
| } | ||
| ], | ||
| "evidence": [ | ||
| { | ||
| "id": "evidence-1", | ||
| "kind": "quote", | ||
| "value": "Kurzer Beleg aus der Leistung" | ||
| } | ||
| ], | ||
| "metadata": { | ||
| "generalComment": "Kurzer Gesamtkommentar" | ||
| } | ||
| } | ||
|
|
||
| JSON structure to output for \`Ende Korrektur\`: | ||
| [ | ||
| { | ||
| "contract": {{contractJson}}, | ||
| "chatRef": "chat-0001", | ||
| "importedTaskScores": [] | ||
| }, | ||
| { | ||
| "contract": {{contractJson}}, | ||
| "chatRef": "chat-0002", | ||
| "importedTaskScores": [] | ||
| } | ||
| ] | ||
|
|
||
| Formatting notes for the JSON structures: | ||
| - replace example \`chatRef\`, \`taskId\`, \`scoringUnitId\`, points, comments, evidence, and metadata with the resolved values | ||
| - use only task IDs and scoring-unit IDs that exist in the loaded contract | ||
| - omit optional fields when they are empty or unsupported | ||
| - for \`Ende Korrektur\`, output only the array and include one object per resolved Leistung | ||
|
|
||
| ## Contract | ||
|
|
||
| {{contractMarkdown}} |
There was a problem hiding this comment.
Inlining the entire contract JSON multiple times inside the prompt's example structures (once in Zwischenexport and twice in Ende Korrektur) will cause massive token bloat and potentially exceed the LLM's context window limits for larger exams.
Instead, we can define a single Contract JSON section at the bottom of the prompt to hold the full contract JSON, and use a placeholder like <contract_json_object> in the examples. This reduces the prompt size significantly while keeping the instructions clear.
JSON structure to output for Zwischenexport:
{
"contract": <contract_json_object>,
"chatRef": "chat-0001",
"importedTaskScores": [
{
"taskId": "task-1",
"points": 0,
"maxPoints": 0,
"scoringUnitId": "task-1.score",
"comment": "Kurzbegruendung mit Bezug zur Leistung",
"confidence": 0.8,
"evidenceIds": ["evidence-1"]
}
],
"evidence": [
{
"id": "evidence-1",
"kind": "quote",
"value": "Kurzer Beleg aus der Leistung"
}
],
"metadata": {
"generalComment": "Kurzer Gesamtkommentar"
}
}
JSON structure to output for Ende Korrektur:
[
{
"contract": <contract_json_object>,
"chatRef": "chat-0001",
"importedTaskScores": []
},
{
"contract": <contract_json_object>,
"chatRef": "chat-0002",
"importedTaskScores": []
}
]
Formatting notes for the JSON structures:
- replace <contract_json_object> with the full JSON object provided in the Contract JSON section below
- replace example chatRef, taskId, scoringUnitId, points, comments, evidence, and metadata with the resolved values
- use only task IDs and scoring-unit IDs that exist in the loaded contract
- omit optional fields when they are empty or unsupported
- for Ende Korrektur, output only the array and include one object per resolved Leistung
## Contract JSON
{{contractJson}}
## Contract
{{contractMarkdown}}| JSON structure to output for `Zwischenexport`: | ||
| { | ||
| "contract": {{contractJson}}, | ||
| "chatRef": "chat-0001", | ||
| "importedTaskScores": [ | ||
| { | ||
| "taskId": "task-1", | ||
| "points": 0, | ||
| "maxPoints": 0, | ||
| "scoringUnitId": "task-1.score", | ||
| "comment": "Kurzbegruendung mit Bezug zur Leistung", | ||
| "confidence": 0.8, | ||
| "evidenceIds": ["evidence-1"] | ||
| } | ||
| ], | ||
| "evidence": [ | ||
| { | ||
| "id": "evidence-1", | ||
| "kind": "quote", | ||
| "value": "Kurzer Beleg aus der Leistung" | ||
| } | ||
| ], | ||
| "metadata": { | ||
| "generalComment": "Kurzer Gesamtkommentar" | ||
| } | ||
| } | ||
|
|
||
| JSON structure to output for `Ende Korrektur`: | ||
| [ | ||
| { | ||
| "contract": {{contractJson}}, | ||
| "chatRef": "chat-0001", | ||
| "importedTaskScores": [] | ||
| }, | ||
| { | ||
| "contract": {{contractJson}}, | ||
| "chatRef": "chat-0002", | ||
| "importedTaskScores": [] | ||
| } | ||
| ] | ||
|
|
||
| Formatting notes for the JSON structures: | ||
| - replace example `chatRef`, `taskId`, `scoringUnitId`, points, comments, evidence, and metadata with the resolved values | ||
| - use only task IDs and scoring-unit IDs that exist in the loaded contract | ||
| - omit optional fields when they are empty or unsupported | ||
| - for `Ende Korrektur`, output only the array and include one object per resolved Leistung | ||
|
|
||
| ## Contract | ||
|
|
||
| {{contractMarkdown}} |
There was a problem hiding this comment.
Inlining the entire contract JSON multiple times inside the prompt's example structures (once in Zwischenexport and twice in Ende Korrektur) will cause massive token bloat and potentially exceed the LLM's context window limits for larger exams.
Instead, we can define a single Contract JSON section at the bottom of the prompt to hold the full contract JSON, and use a placeholder like <contract_json_object> in the examples. This reduces the prompt size significantly while keeping the instructions clear.
JSON structure to output for Zwischenexport:
{
"contract": <contract_json_object>,
"chatRef": "chat-0001",
"importedTaskScores": [
{
"taskId": "task-1",
"points": 0,
"maxPoints": 0,
"scoringUnitId": "task-1.score",
"comment": "Kurzbegruendung mit Bezug zur Leistung",
"confidence": 0.8,
"evidenceIds": ["evidence-1"]
}
],
"evidence": [
{
"id": "evidence-1",
"kind": "quote",
"value": "Kurzer Beleg aus der Leistung"
}
],
"metadata": {
"generalComment": "Kurzer Gesamtkommentar"
}
}
JSON structure to output for Ende Korrektur:
[
{
"contract": <contract_json_object>,
"chatRef": "chat-0001",
"importedTaskScores": []
},
{
"contract": <contract_json_object>,
"chatRef": "chat-0002",
"importedTaskScores": []
}
]
Formatting notes for the JSON structures:
- replace <contract_json_object> with the full JSON object provided in the Contract JSON section below
- replace example chatRef, taskId, scoringUnitId, points, comments, evidence, and metadata with the resolved values
- use only task IDs and scoring-unit IDs that exist in the loaded contract
- omit optional fields when they are empty or unsupported
- for Ende Korrektur, output only the array and include one object per resolved Leistung
## Contract JSON
{{contractJson}}
## Contract
{{contractMarkdown}}| expect(artifact.promptFile.content).toContain('JSON structure to output for `Zwischenexport`'); | ||
| expect(artifact.promptFile.content).toContain('JSON structure to output for `Ende Korrektur`'); | ||
| expect(artifact.promptFile.content).toContain('"contract": {'); | ||
| expect(artifact.promptFile.content).toContain('"id": "contract-session-session-2026-04-17"'); | ||
| expect(artifact.promptFile.content).toContain('"chatRef": "chat-0001"'); | ||
| expect(artifact.promptFile.content).toContain('"importedTaskScores": ['); | ||
| expect(artifact.promptFile.content).toContain('"evidence": ['); | ||
| expect(artifact.promptFile.content).toContain('"metadata": {'); |
There was a problem hiding this comment.
Update the test assertions to match the optimized prompt structure that uses a single Contract JSON section and placeholders in the example structures.
| expect(artifact.promptFile.content).toContain('JSON structure to output for `Zwischenexport`'); | |
| expect(artifact.promptFile.content).toContain('JSON structure to output for `Ende Korrektur`'); | |
| expect(artifact.promptFile.content).toContain('"contract": {'); | |
| expect(artifact.promptFile.content).toContain('"id": "contract-session-session-2026-04-17"'); | |
| expect(artifact.promptFile.content).toContain('"chatRef": "chat-0001"'); | |
| expect(artifact.promptFile.content).toContain('"importedTaskScores": ['); | |
| expect(artifact.promptFile.content).toContain('"evidence": ['); | |
| expect(artifact.promptFile.content).toContain('"metadata": {'); | |
| expect(artifact.promptFile.content).toContain('JSON structure to output for Zwischenexport'); | |
| expect(artifact.promptFile.content).toContain('JSON structure to output for Ende Korrektur'); | |
| expect(artifact.promptFile.content).toContain('"contract": <contract_json_object>'); | |
| expect(artifact.promptFile.content).toContain('"id": "contract-session-session-2026-04-17"'); | |
| expect(artifact.promptFile.content).toContain('"chatRef": "chat-0001"'); | |
| expect(artifact.promptFile.content).toContain('"importedTaskScores": ['); | |
| expect(artifact.promptFile.content).toContain('"evidence": ['); | |
| expect(artifact.promptFile.content).toContain('"metadata": {'); |
There was a problem hiding this comment.
Pull request overview
This PR tightens the “KBR correction-session export” instructions that are generated for ChatGPT so teachers can upload multiple Leistung files at once, and ChatGPT can return results in a stricter, directly importable JSON shape.
Changes:
- Extend contract + prompt instructions to support multiple Leistung uploads per message while keeping each Leistung’s correction data isolated.
- Embed the concrete correction-session
contractJSON into the prompt via a new{{contractJson}}placeholder and pass it from the export use-case. - Add regression assertions to ensure the prompt/contract text includes the new multi-upload and JSON-structure guidance.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| modules/exams/src/use-cases/export-correction-session.use-case.ts | Passes a serialized contractJson into prompt template rendering so prompts can include the real contract object. |
| modules/exams/src/rule-packs/default-pack.ts | Updates the embedded default contract/prompt templates with multi-upload guidance and explicit JSON structures for Zwischenexport / Ende Korrektur. |
| modules/exams/rule-packs/default/prompt.template.md | Mirrors the default prompt template updates in the file-based rule pack template. |
| modules/exams/rule-packs/default/contract.template.md | Mirrors the default contract template updates in the file-based rule pack template. |
| modules/exams/tests/export-correction-session.use-case.test.ts | Adds assertions to lock in the updated prompt/contract content. |
| "points": 0, | ||
| "maxPoints": 0, | ||
| "scoringUnitId": "task-1.score", | ||
| "comment": "Kurzbegruendung mit Bezug zur Leistung", |
| "points": 0, | ||
| "maxPoints": 0, | ||
| "scoringUnitId": "task-1.score", | ||
| "comment": "Kurzbegruendung mit Bezug zur Leistung", |
| expect(artifact.promptFile.content).toContain( | ||
| 'Bitte laden Sie die erste Leistung oder mehrere Leistungen gleichzeitig hoch.' | ||
| ); | ||
| expect(artifact.promptFile.content).toContain( | ||
| 'the user may upload multiple Leistung files in the same message' | ||
| ); |
Summary
This updates the KBR correction-session export instructions generated for ChatGPT so the external correction flow is clearer and directly importable back into ViccoBoard.
Traceability
Changes
ZwischenexportandEnde Korrektur.<contract_json_object>to avoid prompt bloat.Impact
Teachers can upload multiple files to ChatGPT in one correction session, and ChatGPT receives a stricter, concrete JSON target for results that are imported back into KBR.
Validation
npm test --workspace=@viccoboard/exams -- export-correction-session.use-case.test.tsnpm test --workspace=teacher-ui -- kbr-correction-export.test.ts