Enhance test submission feature by adding optional hiddenInstructions field for temporary instructions during LLM checks; update API, UI components, and types to support this functionality, improving task evaluation for teachers and challenge authors.

This commit is contained in:
2025-12-10 14:50:17 +03:00
parent fb25422df1
commit 7b9cb044fa
4 changed files with 18 additions and 12 deletions

View File

@@ -4,7 +4,7 @@
Содержит два блока изменений: Содержит два блока изменений:
- **Управление видимостью цепочек заданий** (поле `isActive` и новый админский эндпоинт). - **Управление видимостью цепочек заданий** (поле `isActive` и новый админский эндпоинт).
- **Тестовая проверка решения задания админом** (флаг `isTest` в `/submit`). - **Тестовая проверка решения задания админом** (флаг `isTest` и опциональные `hiddenInstructions` в `/submit`).
--- ---
@@ -158,14 +158,15 @@
#### `POST /api/challenge/submit` #### `POST /api/challenge/submit`
К существующему API добавлен новый опциональный флаг в теле запроса: К существующему API добавлены новые опциональные поля в теле запроса:
```json ```json
{ {
"userId": "...", "userId": "...",
"taskId": "...", "taskId": "...",
"result": "...", "result": "...",
"isTest": true // НОВОЕ: опциональный флаг "isTest": true, // НОВОЕ: флаг тестового режима
"hiddenInstructions": "..." // НОВОЕ: опциональные инструкции для проверки
} }
``` ```
@@ -183,8 +184,9 @@
- Доступен только для ролей `teacher` / `challenge-author` (проверка через `isTeacher(req, true)`). - Доступен только для ролей `teacher` / `challenge-author` (проверка через `isTeacher(req, true)`).
- **Не создаётся** запись `ChallengeSubmission`. - **Не создаётся** запись `ChallengeSubmission`.
- **Не используется** очередь проверки. - **Не используется** очередь проверки.
- Проверяется только существование задания (`taskId`), пользователь по `userId` в этом режиме **не ищется и не нужен**. - Проверяется только существование задания (`taskId`), пользователь по `userId` в этом режиме **не ищется и не нужен** (но поле всё ещё формально обязательно по схеме).
- Сразу вызывается LLM и возвращается результат проверки. - Если переданы `hiddenInstructions`, они используются **вместо** `task.hiddenInstructions` при формировании промпта для LLM.
- Никакие изменения инструкций, переданные через `hiddenInstructions`, **не сохраняются** в базу — это чисто временная инструкция для одной тестовой проверки.
**Пример запроса (тестовый режим):** **Пример запроса (тестовый режим):**
@@ -197,12 +199,11 @@ Authorization: Bearer <keycloak_token_teacher_or_author>
"userId": "any-or-dummy-id", "userId": "any-or-dummy-id",
"taskId": "507f1f77bcf86cd799439012", "taskId": "507f1f77bcf86cd799439012",
"result": "function solve() { ... }", "result": "function solve() { ... }",
"isTest": true "isTest": true,
"hiddenInstructions": "ВРЕМЕННЫЕ инструкции для проверки, не сохраняются"
} }
``` ```
> `userId` формально обязателен по схеме, но в тестовом режиме не используется на бэке. Можно передавать любой корректный ObjectId.
**Пример ответа (тестовый режим):** **Пример ответа (тестовый режим):**
```json ```json
@@ -222,12 +223,13 @@ Authorization: Bearer <keycloak_token_teacher_or_author>
- **Где использовать тестовый режим**: - **Где использовать тестовый режим**:
- только в админских/преподавательских интерфейсах (например, экран настройки задания или предпросмотр проверки); - только в админских/преподавательских интерфейсах (например, экран настройки задания или предпросмотр проверки);
- использовать флаг `isTest: true`, когда нужно получить мгновенный ответ от LLM без записи в историю. - использовать флаг `isTest: true`, когда нужно получить мгновенный ответ от LLM без записи в историю;
- при наличии UI-редактора скрытых инструкций использовать `hiddenInstructions` для передачи временного варианта, не сохраняя его.
- **Где НЕ использовать**: - **Где НЕ использовать**:
- в пользовательском флоу сдачи заданий студентами — там должен использоваться обычный режим **без** `isTest`. - в пользовательском флоу сдачи заданий студентами — там должен использоваться обычный режим **без** `isTest`.
- **UI-ожидания**: - **UI-ожидания**:
- показывать администратору статус (`accepted` / `needs_revision`) и `feedback`; - показывать администратору статус (`accepted` / `needs_revision`) и `feedback`;
- явно обозначить в интерфейсе, что это «тестовая проверка» и она **не попадает в статистику / попытки**. - явно обозначить в интерфейсе, что это «тестовая проверка» и она **не попадает в статистику / попытки**, а переданные `hiddenInstructions` не сохраняются.
--- ---
@@ -238,4 +240,4 @@ Authorization: Bearer <keycloak_token_teacher_or_author>
- админский список: `GET /api/challenge/chains/admin` → все цепочки + управление `isActive` через `POST/PUT /chain`. - админский список: `GET /api/challenge/chains/admin` → все цепочки + управление `isActive` через `POST/PUT /chain`.
- Для отправки решений: - Для отправки решений:
- обычный режим без `isTest` — всё как раньше (очередь, попытки, статистика); - обычный режим без `isTest` — всё как раньше (очередь, попытки, статистика);
- тестовый режим с `isTest: true` — только для `teacher/challenge-author`, без записи прогресса, сразу возвращает результат проверки. - тестовый режим с `isTest: true` + опциональные `hiddenInstructions` — только для `teacher/challenge-author`, без записи прогресса, сразу возвращает результат проверки с учётом временных инструкций.

View File

@@ -147,7 +147,7 @@ export const api = createApi({
// Test submission (LLM check without creating a real submission) // Test submission (LLM check without creating a real submission)
testSubmission: builder.mutation<TestSubmissionResult, SubmitRequest>({ testSubmission: builder.mutation<TestSubmissionResult, SubmitRequest>({
query: ({ userId, taskId, result, isTest = true }) => ({ query: ({ userId, taskId, result, isTest = true, hiddenInstructions }) => ({
url: '/challenge/submit', url: '/challenge/submit',
method: 'POST', method: 'POST',
body: { body: {
@@ -155,6 +155,7 @@ export const api = createApi({
taskId, taskId,
result, result,
isTest, isTest,
hiddenInstructions,
}, },
}), }),
transformResponse: (response: APIResponse<TestSubmissionResult>) => response.data, transformResponse: (response: APIResponse<TestSubmissionResult>) => response.data,

View File

@@ -136,6 +136,7 @@ export const TaskFormPage: React.FC = () => {
taskId: task.id, taskId: task.id,
result: testAnswer.trim(), result: testAnswer.trim(),
isTest: true, isTest: true,
hiddenInstructions: hiddenInstructions.trim() || undefined,
}).unwrap() }).unwrap()
setTestStatus(result.status) setTestStatus(result.status)

View File

@@ -234,6 +234,8 @@ export interface SubmitRequest {
result: string result: string
// Флаг тестового режима: проверка без создания Submission и очереди // Флаг тестового режима: проверка без создания Submission и очереди
isTest?: boolean isTest?: boolean
// Временные скрытые инструкции для тестовой проверки (не сохраняются в задачу)
hiddenInstructions?: string
} }
export interface TestSubmissionResult { export interface TestSubmissionResult {