From efec383408ebfa641e4812420b8be0577775ea81 Mon Sep 17 00:00:00 2001 From: DickHorner Date: Wed, 27 May 2026 11:06:35 +0200 Subject: [PATCH 1/2] clarify kbr chatgpt import instructions --- .../rule-packs/default/contract.template.md | 3 + .../rule-packs/default/prompt.template.md | 53 +++++++++++++++++- modules/exams/src/rule-packs/default-pack.ts | 56 ++++++++++++++++++- .../export-correction-session.use-case.ts | 1 + ...export-correction-session.use-case.test.ts | 20 +++++++ 5 files changed, 129 insertions(+), 4 deletions(-) diff --git a/modules/exams/rule-packs/default/contract.template.md b/modules/exams/rule-packs/default/contract.template.md index 6d75b9e..b0f9b20 100644 --- a/modules/exams/rule-packs/default/contract.template.md +++ b/modules/exams/rule-packs/default/contract.template.md @@ -15,6 +15,9 @@ ## Matching Rule +- The user may upload multiple Leistung files in the same message. +- Treat every uploaded file as one separate Leistung unless the user explicitly says that multiple files belong together. +- Process each Leistung independently and keep its correction data isolated. - The user does not need to provide a Leistung `chatRef`. - Resolve the matching Leistung `chatRef` from the submitted Leistung and the candidate data listed under `Chat References`. - Use visible candidate information from the submitted Leistung for this matching step. diff --git a/modules/exams/rule-packs/default/prompt.template.md b/modules/exams/rule-packs/default/prompt.template.md index fb09b83..404bd35 100644 --- a/modules/exams/rule-packs/default/prompt.template.md +++ b/modules/exams/rule-packs/default/prompt.template.md @@ -1,10 +1,12 @@ You are assisting with a correction session based on a structured contract. Initial response: -- `Bereit. Bitte laden Sie die erste Leistung hoch.` +- `Bereit. Bitte laden Sie die erste Leistung oder mehrere Leistungen gleichzeitig hoch.` Session workflow (generic and strict): -- process exactly one Leistung at a time +- the user may upload multiple Leistung files in the same message +- treat every uploaded file as one separate Leistung unless the user explicitly says that multiple files belong together +- process one Leistung at a time internally, even when multiple files were uploaded together - keep each Leistung isolated; do not mix data between Leistungen - use the submitted Leistung only to resolve the matching candidate and Leistung `chatRef` - do not require the user to provide a Leistung `chatRef` @@ -56,6 +58,53 @@ Required import bundle fields: - include `importedTaskScores` - include optional fields such as `rulePack`, `evidence`, or `metadata` only when supported by the loaded contract, rules, and import bundle schema +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}} diff --git a/modules/exams/src/rule-packs/default-pack.ts b/modules/exams/src/rule-packs/default-pack.ts index d4ad31c..59dc19b 100644 --- a/modules/exams/src/rule-packs/default-pack.ts +++ b/modules/exams/src/rule-packs/default-pack.ts @@ -83,6 +83,9 @@ const DEFAULT_CONTRACT_TEMPLATE = `# Correction Session Contract ## Matching Rule +- The user may upload multiple Leistung files in the same message. +- Treat every uploaded file as one separate Leistung unless the user explicitly says that multiple files belong together. +- Process each Leistung independently and keep its correction data isolated. - The user does not need to provide a Leistung \`chatRef\`. - Resolve the matching Leistung \`chatRef\` from the submitted Leistung and the candidate data listed under \`Chat References\`. - Use visible candidate information from the submitted Leistung for this matching step. @@ -125,10 +128,12 @@ const DEFAULT_CONTRACT_TEMPLATE = `# Correction Session Contract const DEFAULT_PROMPT_TEMPLATE = `You are assisting with a correction session based on a structured contract. Initial response: -- \`Bereit. Bitte laden Sie die erste Leistung hoch.\` +- \`Bereit. Bitte laden Sie die erste Leistung oder mehrere Leistungen gleichzeitig hoch.\` Session workflow (generic and strict): -- process exactly one Leistung at a time +- the user may upload multiple Leistung files in the same message +- treat every uploaded file as one separate Leistung unless the user explicitly says that multiple files belong together +- process one Leistung at a time internally, even when multiple files were uploaded together - keep each Leistung isolated; do not mix data between Leistungen - use the submitted Leistung only to resolve the matching candidate and Leistung \`chatRef\` - do not require the user to provide a Leistung \`chatRef\` @@ -180,6 +185,53 @@ Required import bundle fields: - include \`importedTaskScores\` - include optional fields such as \`rulePack\`, \`evidence\`, or \`metadata\` only when supported by the loaded contract, rules, and import bundle schema +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}} diff --git a/modules/exams/src/use-cases/export-correction-session.use-case.ts b/modules/exams/src/use-cases/export-correction-session.use-case.ts index bfb3c40..5134b80 100644 --- a/modules/exams/src/use-cases/export-correction-session.use-case.ts +++ b/modules/exams/src/use-cases/export-correction-session.use-case.ts @@ -95,6 +95,7 @@ function buildPromptArtifacts( ): string { return renderTemplate(rulePack.templates.prompt, { contractMarkdown, + contractJson: JSON.stringify(contract, null, 2), importBundleSchema: JSON.stringify(rulePack.importBundleSchema, null, 2), rulePackManifest: JSON.stringify(rulePack.manifest, null, 2), rulePackRules: JSON.stringify(rulePack.rules, null, 2), diff --git a/modules/exams/tests/export-correction-session.use-case.test.ts b/modules/exams/tests/export-correction-session.use-case.test.ts index 644c8df..02a9b52 100644 --- a/modules/exams/tests/export-correction-session.use-case.test.ts +++ b/modules/exams/tests/export-correction-session.use-case.test.ts @@ -215,6 +215,26 @@ describe('ExportCorrectionSessionArtifactsUseCase', () => { expect(artifact.promptFile.content).toContain('"importedTaskScores"'); expect(artifact.promptFile.content).toContain('must return exactly one raw JSON array'); expect(artifact.promptFile.content).toContain('do not invent a wrapper object'); + 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' + ); + 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.contractFile.content).toContain( + 'The user may upload multiple Leistung files in the same message.' + ); + expect(artifact.contractFile.content).toContain( + 'Process each Leistung independently and keep its correction data isolated.' + ); }); it('does not require users to provide Leistung chatRefs before evaluation', () => { From 03092e06c46d6d9923f6221ecc0f1beedbd5a65e Mon Sep 17 00:00:00 2001 From: DickHorner Date: Wed, 27 May 2026 11:26:55 +0200 Subject: [PATCH 2/2] address kbr prompt review feedback --- modules/exams/rule-packs/default/prompt.template.md | 13 +++++++++---- modules/exams/src/rule-packs/default-pack.ts | 13 +++++++++---- .../export-correction-session.use-case.test.ts | 7 ++++++- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/modules/exams/rule-packs/default/prompt.template.md b/modules/exams/rule-packs/default/prompt.template.md index 404bd35..b6d8579 100644 --- a/modules/exams/rule-packs/default/prompt.template.md +++ b/modules/exams/rule-packs/default/prompt.template.md @@ -60,7 +60,7 @@ Required import bundle fields: JSON structure to output for `Zwischenexport`: { - "contract": {{contractJson}}, + "contract": , "chatRef": "chat-0001", "importedTaskScores": [ { @@ -68,7 +68,7 @@ JSON structure to output for `Zwischenexport`: "points": 0, "maxPoints": 0, "scoringUnitId": "task-1.score", - "comment": "Kurzbegruendung mit Bezug zur Leistung", + "comment": "Kurzbegründung mit Bezug zur Leistung", "confidence": 0.8, "evidenceIds": ["evidence-1"] } @@ -88,23 +88,28 @@ JSON structure to output for `Zwischenexport`: JSON structure to output for `Ende Korrektur`: [ { - "contract": {{contractJson}}, + "contract": , "chatRef": "chat-0001", "importedTaskScores": [] }, { - "contract": {{contractJson}}, + "contract": , "chatRef": "chat-0002", "importedTaskScores": [] } ] Formatting notes for the JSON structures: +- replace `` 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}} diff --git a/modules/exams/src/rule-packs/default-pack.ts b/modules/exams/src/rule-packs/default-pack.ts index 59dc19b..97c8676 100644 --- a/modules/exams/src/rule-packs/default-pack.ts +++ b/modules/exams/src/rule-packs/default-pack.ts @@ -187,7 +187,7 @@ Required import bundle fields: JSON structure to output for \`Zwischenexport\`: { - "contract": {{contractJson}}, + "contract": , "chatRef": "chat-0001", "importedTaskScores": [ { @@ -195,7 +195,7 @@ JSON structure to output for \`Zwischenexport\`: "points": 0, "maxPoints": 0, "scoringUnitId": "task-1.score", - "comment": "Kurzbegruendung mit Bezug zur Leistung", + "comment": "Kurzbegründung mit Bezug zur Leistung", "confidence": 0.8, "evidenceIds": ["evidence-1"] } @@ -215,23 +215,28 @@ JSON structure to output for \`Zwischenexport\`: JSON structure to output for \`Ende Korrektur\`: [ { - "contract": {{contractJson}}, + "contract": , "chatRef": "chat-0001", "importedTaskScores": [] }, { - "contract": {{contractJson}}, + "contract": , "chatRef": "chat-0002", "importedTaskScores": [] } ] Formatting notes for the JSON structures: +- replace \`\` 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}} diff --git a/modules/exams/tests/export-correction-session.use-case.test.ts b/modules/exams/tests/export-correction-session.use-case.test.ts index 02a9b52..85cd472 100644 --- a/modules/exams/tests/export-correction-session.use-case.test.ts +++ b/modules/exams/tests/export-correction-session.use-case.test.ts @@ -223,12 +223,17 @@ describe('ExportCorrectionSessionArtifactsUseCase', () => { ); 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('"contract": '); + expect(artifact.promptFile.content).toContain('## Contract JSON'); expect(artifact.promptFile.content).toContain('"id": "contract-session-session-2026-04-17"'); + expect( + artifact.promptFile.content.match(/"id": "contract-session-session-2026-04-17"/g) + ).toHaveLength(1); 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('Kurzbegründung mit Bezug zur Leistung'); expect(artifact.contractFile.content).toContain( 'The user may upload multiple Leistung files in the same message.' );