Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
289 commits
Select commit Hold shift + click to select a range
891875b
Temporary fix: adapt to spring-ai Azure module removal on develop
DominikRemo Jun 18, 2026
d1aa5e8
Exercise variants: remove group-level competency management
DominikRemo Jun 18, 2026
8fd80a0
Exercise variants: fix export modal footer and create-type routing
Jun 18, 2026
c25230b
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jun 18, 2026
451802c
Revert "Temporary fix: adapt to spring-ai Azure module removal on dev…
DominikRemo Jun 18, 2026
9131fcb
Merge branch 'develop' into feature/exercise-variants-support
DominikRemo Jun 18, 2026
bd5ca48
Exercise variants: improve group sidebar and detail page UX
Jun 19, 2026
475529f
Exercise variants: defer group creation until edit modal is confirmed
Jun 19, 2026
7b9f87d
Merge branch 'develop' into feature/exercise-variants-support
DominikRemo Jun 25, 2026
543f381
Exercise variants: relocate quiz status badge and remove deleted rows…
Jun 25, 2026
7137eda
Development: Refine exercise management table column widths and scrol…
DominikRemo Jun 25, 2026
25f9f2e
wip quiz buttons
Jun 25, 2026
fc90e5c
Development: Render exercise group dropdown via appendTo body to fix …
DominikRemo Jun 25, 2026
a77198f
Exercise variants: add group deletion and consolidate group i18n
DominikRemo Jun 25, 2026
87e57d5
Exercise variants: modern quiz lifecycle buttons with batches popover
Jun 25, 2026
2fa27b8
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jun 25, 2026
499df77
Exercise variants: share action-button width measurement across rows
Jun 25, 2026
a421d6c
Exercise variants: validate group timelines and expose all group dates
DominikRemo Jun 25, 2026
1d3c536
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jun 25, 2026
f52cac9
Exercise variants: replace experimental student view with production …
DominikRemo Jun 26, 2026
7f18b50
Exercise variants: responsive, translated action bar with overflow menu
Jun 26, 2026
f5c61a2
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jun 26, 2026
6bbcdef
Exercise variants: redesign student group detail view with exercise h…
DominikRemo Jun 26, 2026
3774e61
Merge branch 'feature/exercise-variants-support' of https://github.co…
DominikRemo Jun 26, 2026
8eca13e
add management view translations
Jun 26, 2026
ce00874
Exercise variants: improve student group detail view info fields
DominikRemo Jun 27, 2026
dedb0ea
Exercise variants: fix and complete i18n for client and server
DominikRemo Jun 27, 2026
1d011bb
Exercise variants: remove group import from add modal; fix tab reset …
DominikRemo Jun 27, 2026
bd0f393
Exercise variants: group-edit modal via DialogService + timeline lock
Jun 28, 2026
de179f4
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jun 28, 2026
26ebce4
Merge branch 'develop' into feature/exercise-variants-support
Jun 28, 2026
7e8722f
Exercise variants: remember selected management view
Jun 28, 2026
cd8acb0
Exercise variants: lifecycle buttons in own component; quiz edit disa…
DominikRemo Jun 28, 2026
3b40bbb
Polish exercise management view layout
Jun 28, 2026
70cb37b
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jun 28, 2026
1443146
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jun 28, 2026
ab61659
remove mock data
Jun 28, 2026
5d685f9
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jun 28, 2026
670af73
Exercise variants: relocate management view out of core/
Jun 28, 2026
ae5ea12
Exercise management: wire up mass actions
Jun 28, 2026
2971728
Exercise management: keep quiz lifecycle buttons visible
Jun 29, 2026
f05038f
Exercise variants: cap group points in course score
Jun 29, 2026
05b80ba
Exercise variants: show total vs credited points in statistics
Jun 30, 2026
5fbafa5
Exercise variants: complete javadoc on group repository query
Jun 30, 2026
eadb058
Exercise variants: show excess variant points on scores page
Jun 30, 2026
fc7b8ab
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 3, 2026
95d69a5
Exercise variants: fix architecture test and add unit tests
Jul 3, 2026
b2dea17
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jul 3, 2026
c334765
Exercise variants: remove unsafe `as unknown` casts flagged by lint
DominikRemo Jul 3, 2026
1715c0d
Exercise management: remove dead code from the old exercise table
Jul 3, 2026
d617e87
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jul 3, 2026
479f53b
Exercise variants: fix E2E selectors for redesigned exercise management
DominikRemo Jul 3, 2026
e64cad5
Exercise variants: fix Codacy stylelint issues in SCSS
DominikRemo Jul 3, 2026
da6386c
Exercise variants: address review feedback on management and student UI
Jul 3, 2026
868140d
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jul 3, 2026
c53a795
Merge remote-tracking branch 'origin/develop' into feature/exercise-v…
Jul 3, 2026
10aa441
Client: fix ESLint errors in course exercise management
Jul 3, 2026
fc9a3d3
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 3, 2026
14e930a
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jul 3, 2026
1403ffe
Exercise variants: re-add AI variant creation button as a UI-only wizard
DominikRemo Jul 3, 2026
9318a0b
Exercise variants: add AI variants generation implementation plan
DominikRemo Jul 3, 2026
d0dc27c
Client: replace non-null assertions with type narrowing
Jul 4, 2026
66210bc
Merge remote-tracking branch 'origin/develop' into feature/exercise-v…
Jul 4, 2026
55c25b5
Exercise variants: update AI variants generation implementation plan
DominikRemo Jul 4, 2026
6324732
Exercise variants: scaffold AI variants generation architecture
DominikRemo Jul 4, 2026
6d036c8
Exercise variant groups: address PR review findings
Jul 4, 2026
0961a2d
Exercise variants: implement job infrastructure and generation pipeline
DominikRemo Jul 4, 2026
bec47c9
Exercise variants: implement programming adapters and shared placement
Jul 4, 2026
2a4821d
Exercise variants: fix compile error and review findings in adapters
DominikRemo Jul 4, 2026
8460097
Exercise variants: address remaining review findings in the agent too…
DominikRemo Jul 4, 2026
c9f04cf
Exercise variants: implement quiz adapters and LLM token accounting
DominikRemo Jul 4, 2026
a585114
Exercise variants: wire client to real jobs, add prompts and critique…
DominikRemo Jul 5, 2026
4d86f7c
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 6, 2026
d3bd568
Exercise variants: fix generation runtime, enable parallel jobs
DominikRemo Jul 6, 2026
162fb3a
Exercise variants: address code review findings
Jul 6, 2026
140bdbc
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 6, 2026
780b974
Exercise management: extract bucket building and group sync from exer…
Jul 6, 2026
8ac2884
Exercise management: rename bucket concept to course exercise card
Jul 6, 2026
d1fe358
Exercise variants: overhaul tray/modal UX, add AI failure post-mortem
DominikRemo Jul 6, 2026
8d3edc0
Exercise variants: implement pipeline integration tests, fix quiz JSON
DominikRemo Jul 7, 2026
9ddf24f
Exercise variants: track critique tokens, show token totals in modal
DominikRemo Jul 7, 2026
4625d36
Exercise management: extract and rename bucket building and group syn…
Jul 6, 2026
a9e67a9
Exercise variants: address review findings on gating, a11y and error …
Jul 6, 2026
087335a
Exercise variants: document mixed-type groups and non-transactional c…
Jul 7, 2026
69c3c6e
Exercise variants: use server-computed result for the group points pr…
Jul 7, 2026
ecf18fd
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 7, 2026
2d4bfea
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jul 7, 2026
1120245
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 7, 2026
3461f6d
Exercise variants: fix programming provisioning, clarify prompts
DominikRemo Jul 7, 2026
ea8a86f
Exercise variants: fix quiz date validation, group timeline UX and ta…
Jul 7, 2026
02f8b6e
Merge branch 'develop' into feature/exercise-variants-support
Jul 7, 2026
cd446d7
Exercise variants: validate member timelines before saving group update
Jul 7, 2026
94dddfd
fix client code style
Jul 7, 2026
61d99ed
Exercise variants: green programming run verified, truncate warning logs
DominikRemo Jul 7, 2026
57ac276
Exercise variants: add implementation state report and roadmap
DominikRemo Jul 7, 2026
2d9259a
Exercise variants: raise client test coverage and fix changelog order
Jul 7, 2026
9b62e32
Exercise variants: type delete mocks as HttpResponse<void> in actions…
Jul 7, 2026
97418b0
Exercise variants: clear stale groups for non-editor courses
Jul 8, 2026
f3f388c
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 8, 2026
3b7487f
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jul 8, 2026
2eb735c
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 9, 2026
25728b6
Exercise variants: restore quiz batch button ids for E2E
Jul 9, 2026
448e0dd
Exercise variants: fix stale quiz flags and speed up group lookup
Jul 10, 2026
c30e882
Merge branch 'feature/exercise-variants-support' into feature/exercis…
DominikRemo Jul 10, 2026
5e9a16d
Exercise variants: bring programming-timeline handling into ExerciseV…
DominikRemo Jul 10, 2026
a60ae15
@
Jul 10, 2026
d10e7c9
Exercise variants: add OnPush and precompute row view models
Jul 13, 2026
10f9f55
Exercise variants: move new styling to theme tokens and PrimeNG
Jul 13, 2026
7d6f59d
Exercise variants: replace object spreads with explicit construction
Jul 13, 2026
dd8d87f
Exercise variants: use the translate directive and prefer undefined o…
Jul 13, 2026
ed4b817
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 13, 2026
50f3ef7
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jul 13, 2026
552f21b
Exercise variants: remove non-null assertions and Bootstrap class com…
Jul 13, 2026
65f40b5
Exercise variants: extract the variant-group capped sum into its own …
Jul 13, 2026
c890563
Exercise variants: move the group timeline logic into a service
Jul 13, 2026
41fc4a1
Exercise variants: exam entry point + live-tested generation fixes
DominikRemo Jul 14, 2026
a888074
Exercise variants: load the variant group lazily
Jul 14, 2026
9a7ec6a
Exercise variants: Vitest spec for the exam wizard path
DominikRemo Jul 14, 2026
99d851d
Exercise variants: carry the variant group on the per-type edit endpo…
Jul 14, 2026
bb4f282
Exercise variants: Playwright E2E against a mocked-LLM profile
DominikRemo Jul 14, 2026
701a172
Exercise variants: never map an unfetched variant group
Jul 14, 2026
5573f70
Exercise variants: VerificationReport gate enum + comment cleanup
DominikRemo Jul 14, 2026
fdcd4ce
Exercise variants: show uncapped points in the course scores table
Jul 14, 2026
0074f53
Exercise variants: polish the exercise management UI
Jul 16, 2026
fe6252a
Merge remote-tracking branch 'origin/develop' into feature/exercise-v…
Jul 16, 2026
736b117
Reformat merged files for the upgraded Prettier config
Jul 16, 2026
8007829
Exercise variants: resolve remaining server-side TODOs
DominikRemo Jul 16, 2026
ed527ca
Migrate exercise-variant specs to the Angular 22 test setup
Jul 16, 2026
2a94992
Exercise variants: strip plan/scratch citations from client + test co…
DominikRemo Jul 16, 2026
e427c36
Exercise variants: block bulk timeline edit for group members
Jul 16, 2026
d90a376
Exercise variants: drop the last stale assignment TODO on the request…
DominikRemo Jul 16, 2026
430c27e
Exercise variants: correct the student group-detail points
Jul 16, 2026
a5ebd90
Exercise variants: regenerate OpenAPI spec + variant client from server
DominikRemo Jul 16, 2026
1b3563c
Exercises: drop redundant EntityGraph root paths to fix query quality
Jul 16, 2026
b84faac
Exercise variants: don't persist a group before its members validate
DominikRemo Jul 16, 2026
f42bad7
Exercise variants: let the agent edit every file in a repository
DominikRemo Jul 17, 2026
3d82794
Exercise variants: only offer AI generation for supported exercises
DominikRemo Jul 17, 2026
0d217c6
Client: correct over-eager reformat of merge-affected files
Jul 17, 2026
518b0df
Course scores: include uncapped variant groups in the group-detail po…
Jul 17, 2026
93b3347
Exercise variants: hide the new-group placement when the source can't…
DominikRemo Jul 17, 2026
297818f
Exercise variants: allow difficulty adaptation for exam exercises
DominikRemo Jul 17, 2026
ce5f64c
Exercise variants: drop the placement step from the exam wizard indic…
DominikRemo Jul 17, 2026
a45e18d
Exercise variants: add a storytelling setting to the wizard
DominikRemo Jul 17, 2026
ae65ff0
Merge remote-tracking branch 'origin/develop' into feature/exercise-v…
Jul 19, 2026
1f5ee10
Exercises: Address review findings on variant group support
Jul 19, 2026
30f67f9
Exercises: Restore repo/build-plan cleanup checks in row delete dialog
Jul 20, 2026
bca84dc
Exercise variants: keep the full step-output history per phase
DominikRemo Jul 20, 2026
170f7cf
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
DominikRemo Jul 20, 2026
e2ab4fe
Exercise variants: migrate variant OpenAPI client to kebab-case naming
DominikRemo Jul 20, 2026
199235e
Exercises: Enforce variant group timeline on exercise update paths
Jul 20, 2026
7b5abd2
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 20, 2026
5d7594a
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jul 20, 2026
cf4f289
Exercise variants: drop per-spec setupTestBed after global TestBed mi…
DominikRemo Jul 20, 2026
9b08a49
Exercise variants: open a fresh wizard for each parallel generation
DominikRemo Jul 20, 2026
a9b66cd
Exercise variants: open the generated variant in its editor from the …
DominikRemo Jul 20, 2026
7cee493
Exercise variants: batch programming edits into one applyEdits call
DominikRemo Jul 20, 2026
27d7a16
Exercises: Include variant group members in sidebar search
Jul 20, 2026
a1f8790
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 20, 2026
c7acd48
Exercise variants: verify solution and template builds concurrently
DominikRemo Jul 20, 2026
fcacb71
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 20, 2026
109c8cb
Exercise variants: batch quiz question replacement into one call
DominikRemo Jul 20, 2026
f2747b7
Exercises: Address variant-group timeline review findings
Jul 21, 2026
08345af
Exercises: Guard grouped individual-quiz timelines against locked edits
Jul 21, 2026
5ab1d0e
Exercises: Expand sidebar category for directly-selected variant
Jul 21, 2026
0ef4955
Merge remote-tracking branch 'origin/develop' into feature/exercise-v…
Jul 21, 2026
67c2bfb
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 21, 2026
a45816a
Exercises: Batch variant-group member problem statements
Jul 21, 2026
44ccd1e
Exercises: Fix build and architecture violations in variant-group batch
Jul 21, 2026
d01296d
Exercise variants: batch edits/writes/deletes across all repositories…
DominikRemo Jul 23, 2026
df9013c
Exercise variants: add a source-diff tool and trust the agent with fu…
DominikRemo Jul 23, 2026
1682236
Exercise variants: forbid comment-only domain re-themes in planning/t…
DominikRemo Jul 23, 2026
6530cd5
Exercise variants: baseline per-tool-call and per-build timing on the…
DominikRemo Jul 23, 2026
122e7e2
Exercise variants: skip the redundant VERIFYING rebuild on a matched …
DominikRemo Jul 23, 2026
45cc162
Exercise variants: prefetch repository context into the transform round
DominikRemo Jul 23, 2026
2ac6ea7
Exercise variants: fix template scaffolding, test deletion, and test-…
DominikRemo Jul 23, 2026
dc3322f
Exercise variants: parallel-tool-call nudge + fix more rename-consist…
DominikRemo Jul 23, 2026
364f831
Exercise variants: consolidate the transform prompt instead of growin…
DominikRemo Jul 23, 2026
a73efb1
Merge remote-tracking branch 'origin/develop' into feature/exercise-v…
Jul 24, 2026
3ac57c9
Exercises: Tighten and trim variant-group comments
Jul 24, 2026
fa6a2d9
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 24, 2026
f867076
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jul 24, 2026
d1fcb20
Exercises: Migrate the variant UI to the TUM UI kit (part 1)
Jul 24, 2026
b09e892
Exercise variants: parallelize verification gates, fix scaffolding/ra…
DominikRemo Jul 24, 2026
4aed157
Exercises: Migrate the exercise table to the TUM UI kit (part 2)
Jul 24, 2026
9a5c83a
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 25, 2026
0db81b2
Exercises: Finish the exercise table on the TUM UI kit (part 3)
Jul 25, 2026
9bbcad1
Exercises: Move the exercise-actions overflow menu to the UI kit
Jul 25, 2026
0292ee4
Exercises: Migrate quiz lifecycle buttons to the UI kit; fix disabled…
Jul 25, 2026
ac05449
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
Jul 25, 2026
6b94c39
Exercises: Convert the programmatic dialogs to declarative tum-ui-dialog
Jul 26, 2026
fef2091
Exercises: Fix editor gate and sidebar tracking for exercise variants
Jul 26, 2026
1ec34a1
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 27, 2026
89db662
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
DominikRemo Jul 27, 2026
a07ef86
Exercise variants: migrate variant-generation UI to the TUM UI kit
DominikRemo Jul 27, 2026
41025ad
Exercise variants: replace raw Bootstrap CSS vars/hex with semantic t…
DominikRemo Jul 27, 2026
d06d1a1
Exercise variants: drop unused buildAndTestStudentSubmissionsAfterDue…
DominikRemo Jul 27, 2026
ee2215b
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 28, 2026
6debc3f
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 28, 2026
293ad0d
Exercises: Finish the exercise management TUM UI kit migration
Jul 28, 2026
48e4726
Merge remote-tracking branch 'origin/develop' into feature/exercise-v…
Jul 28, 2026
f1f51b3
Merge branch 'develop' into feature/exercise-variants-support
laadvo Jul 28, 2026
a50da95
Exercise variants: extract shared exercise action bar
DominikRemo Jul 28, 2026
ee4d85e
Exam mode: rework exercise group management and allow moving exercises
DominikRemo Jul 28, 2026
39417d1
Exercise variants: summarize flagged drafts and fix the task-link gate
DominikRemo Jul 28, 2026
4f8a46a
Merge remote-tracking branch 'origin/feature/exercise-variants-suppor…
DominikRemo Jul 28, 2026
a62a286
Exercise variants: migrate the remaining UI off PrimeNG and Bootstrap
DominikRemo Jul 28, 2026
19f7087
Exercise variants: keep the AI button on Bootstrap in its Bootstrap rows
DominikRemo Jul 28, 2026
56eeb33
Exercise variants: loosen the wizard's step and footer spacing
DominikRemo Jul 28, 2026
8bdb264
Exercise variants: register the migrated modules with Tailwind's sour…
DominikRemo Jul 28, 2026
29daebc
Exercise variants: restore the tray toggle's navbar look without Boot…
DominikRemo Jul 28, 2026
a9842e3
Exercise variants: let the new-group title input fill its row
DominikRemo Jul 28, 2026
c1b6a39
TUM UI: Keep dialogs from burying overlays opened inside them
Jul 29, 2026
473b1ac
Merge branch 'feature/exercise-variants-support' into feature/exercis…
DominikRemo Jul 29, 2026
6ae72ea
Exercise variants: make programming variant generation reliable
DominikRemo Jul 29, 2026
a417996
Exercise variants: log the phase timeline
DominikRemo Aug 5, 2026
b8d77a7
Exercise variants: rebuild short-answer mappings on question replace
DominikRemo Aug 5, 2026
f8bbc1b
Exercise variants: make generated variants graded and buildable
DominikRemo Aug 5, 2026
8b6c9ee
Exercise variants: add the generation evaluation harness
DominikRemo Aug 5, 2026
e313662
Exercise variants: report matrix progress while it runs
DominikRemo Aug 5, 2026
84479eb
Exercise variants: add the evaluation results and analysis outputs
DominikRemo Aug 6, 2026
b40f424
Exercise variants: hand the qualitative analysis off to a second session
DominikRemo Aug 6, 2026
38e326e
Exercise variants: spell out the clone-and-go setup in the handoff
DominikRemo Aug 6, 2026
da2caa9
Exercise variants: raise the short-name collision retry budget
DominikRemo Aug 6, 2026
6e7e6d9
Exercise variants: score all 168 variants and write the evaluation re…
Aug 6, 2026
4b95f92
Add todo-evaluation-artemis.md
DominikRemo Aug 6, 2026
9fbe377
Merge remote-tracking branch 'origin/feature/exercise-variants-ai-gen…
Aug 6, 2026
f57a0e7
Exercise variants: align report with the original work order's section 6
Aug 6, 2026
2ae3cec
Merge remote-tracking branch 'origin/develop' into feature/exercise-v…
DominikRemo Aug 11, 2026
b203bf4
Exam mode: revert the exercise group redesign, keep the AI variant ac…
DominikRemo Aug 11, 2026
0bdcdf2
Merge remote-tracking branch 'origin/develop' into feature/exercise-v…
Aug 13, 2026
a16e30e
Exercises: Recolor the AI variant generation UI
Aug 13, 2026
664bfc0
Exercises: Tokenize the AI variant wizard elevation shadows
Aug 14, 2026
76321a8
Exercises: Restore the width of the exercise management dialogs
Aug 14, 2026
7ac1c31
Exercises: drop planning docs from the branch
Aug 17, 2026
0c5ce6f
Exercises: clean up evaluation files
Aug 17, 2026
af1497b
Merge remote-tracking branch 'origin/develop' into feature/exercise-v…
DominikRemo Aug 18, 2026
82af578
Timeline: match develop's comment style to minimize the merge diff
DominikRemo Aug 18, 2026
96831dd
Revert comment-only diffs to minimize the merge diff
Aug 18, 2026
8258960
Exercise variants: shrink ProgrammingVariantTools below the size limit
Aug 18, 2026
57f79d2
Exercise variants: drop changes unrelated to the feature
DominikRemo Aug 20, 2026
ce433ff
Programming exercises: restore the task test-name replacement tests
DominikRemo Aug 20, 2026
d326d8c
Exercise variants: trim the OpenAPI spec to the variant endpoints
DominikRemo Aug 20, 2026
e113919
Exercise variants: add the AI button without the shared action bar
DominikRemo Aug 20, 2026
fd35a79
Exercise variants: fix generation broken by the develop merge
DominikRemo Aug 20, 2026
9d02483
Merge branch 'develop' into feature/exercise-variants-ai-generation
Aug 24, 2026
c8eb276
Exercise variants: satisfy the module architecture rules
Aug 24, 2026
2e62b77
Exercise variants: close the review's correctness gaps
Aug 24, 2026
97730e1
Exercise variants: de-flake the cancellation test and drop dead code
Aug 24, 2026
1224909
Exercise variants: make the wizard operable by keyboard
Aug 24, 2026
4545774
Exercise variants: address the latest review round
Aug 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 147 additions & 0 deletions openapi/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,63 @@ paths:
content:
application/json:
schema: {$ref: '#/components/schemas/ConsistencyCheckResponse'}
/api/hyperion/exercises/{exerciseId}/generate-variant:
post:
tags: [hyperion-exercise-variant]
operationId: generateVariant
parameters:
- name: exerciseId
in: path
required: true
schema: {type: integer, format: int64}
requestBody:
content:
application/json:
schema: {$ref: '#/components/schemas/VariantGenerationRequest'}
required: true
responses:
'200':
description: OK
content:
application/json:
schema: {$ref: '#/components/schemas/VariantJobStart'}
/api/hyperion/variant-jobs:
get:
tags: [hyperion-exercise-variant]
operationId: getJobsOfCurrentUser
responses:
'200':
description: OK
content:
application/json:
schema:
type: array
items: {$ref: '#/components/schemas/VariantJob'}
/api/hyperion/variant-jobs/{jobId}:
get:
tags: [hyperion-exercise-variant]
operationId: getJobDetail
parameters:
- name: jobId
in: path
required: true
schema: {type: string}
responses:
'200':
description: OK
content:
application/json:
schema: {$ref: '#/components/schemas/VariantJobDetail'}
delete:
tags: [hyperion-exercise-variant]
operationId: cancelJob
parameters:
- name: jobId
in: path
required: true
schema: {type: string}
responses:
'200': {description: OK}
/api/hyperion/courses/{courseId}/assessment-criteria/generate:
post:
tags: [hyperion-assessment-criteria-generation]
Expand Down Expand Up @@ -3005,3 +3062,93 @@ components:
userPrompt: {type: string, description: User prompt for global refinement,
maxLength: 1000, minLength: 1}
required: [problemStatementText, userPrompt]
VariantJob:
type: object
properties:
jobId: {type: string}
sourceExerciseId: {type: integer, format: int64}
courseId: {type: integer, format: int64}
sourceExerciseTitle: {type: string}
exerciseType:
type: string
enum: [text, programming, modeling, file-upload, quiz]
phase:
type: string
enum: [ANALYZING, PLANNING, PROVISIONING, TRANSFORMING, VERIFYING, REPAIRING,
FINALIZING, COMPLETED, DRAFT_WITH_WARNINGS, FAILED, CANCELLED]
failedInPhase:
type: string
enum: [ANALYZING, PLANNING, PROVISIONING, TRANSFORMING, VERIFYING, REPAIRING,
FINALIZING, COMPLETED, DRAFT_WITH_WARNINGS, FAILED, CANCELLED]
failureDetail: {type: string}
instructorSummary: {type: string}
attempt: {type: integer, format: int32}
maxAttempts: {type: integer, format: int32}
variantExerciseId: {type: integer, format: int64}
variantExerciseTitle: {type: string}
request: {$ref: '#/components/schemas/VariantGenerationRequest'}
warnings:
type: array
items: {type: string}
totalTokensUsed: {type: integer, format: int64}
startedAt: {type: string, format: date-time}
finishedAt: {type: string, format: date-time}
VariantJobStart:
type: object
properties:
jobId: {type: string}
CreateExerciseVariantGroup:
type: object
properties:
title: {type: string, minLength: 1}
maxPoints: {type: number, format: double}
releaseDate: {type: string, format: date-time}
startDate: {type: string, format: date-time}
dueDate: {type: string, format: date-time}
assessmentDueDate: {type: string, format: date-time}
exampleSolutionPublicationDate: {type: string, format: date-time}
buildAndTestStudentSubmissionsAfterDueDate: {type: string, format: date-time}
required: [title]
VariantPlacement:
type: object
properties:
type:
type: string
enum: [EXISTING_GROUP, NEW_GROUP, STANDALONE, SAME_EXAM_GROUP]
existingGroupId:
type: [integer, 'null']
format: int64
newGroup: {$ref: '#/components/schemas/CreateExerciseVariantGroup'}
VariantJobDetail:
type: object
properties:
job: {$ref: '#/components/schemas/VariantJob'}
stepOutputs:
type: object
additionalProperties:
type: array
items: {$ref: '#/components/schemas/StepOutput'}
request: {$ref: '#/components/schemas/VariantGenerationRequest'}
StepOutput:
type: object
properties:
summary: {type: string}
detail: {type: string}
VariantGenerationRequest:
type: object
properties:
targetDifficulty:
type: [string, 'null']
enum: [EASY, MEDIUM, HARD]
domainText:
type: [string, 'null']
maxLength: 2000
minLength: 0
narrativeStyle:
type: [string, 'null']
enum: [TECHNICAL, REALISTIC, CREATIVE, IMAGINATIVE]
additionalInstructions:
type: [string, 'null']
maxLength: 2000
minLength: 0
placement: {$ref: '#/components/schemas/VariantPlacement'}
65 changes: 65 additions & 0 deletions run-e2e-tests-local-fast.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,17 @@ IRIS_ARTEMIS_CALLBACK_URL="${IRIS_ARTEMIS_CALLBACK_URL:-http://host.docker.inter
# The Iris-enabled seed course whose course-level Iris settings get turned on.
IRIS_COURSE_ID="${IRIS_COURSE_ID:-9022}"

# Hyperion (AI exercise-variant generation) e2e support: when RUN_HYPERION=true the
# runner starts a deterministic OpenAI-compatible mock LLM (a bare Python process, see
# src/test/playwright/support/hyperion-mock-llm/) and enables Hyperion on the Artemis
# server pointed at it via spring.ai.openai.*. Unlike Iris, Hyperion talks to the LLM
# directly through Spring AI, so no microservice is needed — just the mock. Off by
# default so normal runs are unaffected. Run the variant suite with:
# RUN_HYPERION=true ./run-e2e-tests-local-fast.sh --filter "Variant"
RUN_HYPERION="${RUN_HYPERION:-false}"
HYPERION_MOCK_LLM_SCRIPT="src/test/playwright/support/hyperion-mock-llm/mock_llm.py"
HYPERION_MOCK_LLM_PORT="${HYPERION_MOCK_LLM_PORT:-8090}"

while [[ $# -gt 0 ]]; do
case $1 in
--stop) STOP=true; shift ;;
Expand Down Expand Up @@ -189,6 +200,15 @@ if [ "$STOP" = true ]; then
docker compose -f "$IRIS_STACK_COMPOSE" down -v 2>/dev/null || true
fi

# Stop the Hyperion mock LLM if it is running (bare Python process)
if [ -f "$LOCAL_DIR/hyperion-mock-llm.pid" ]; then
MOCK_PID=$(cat "$LOCAL_DIR/hyperion-mock-llm.pid")
if kill -0 "$MOCK_PID" 2>/dev/null; then
echo "Stopping Hyperion mock LLM (PID $MOCK_PID)..."
kill_tree "$MOCK_PID"
fi
fi

# Stop Postgres
echo "Stopping Postgres..."
docker compose --env-file .env -f "$COMPOSE_FILE" down -v 2>/dev/null || true
Expand Down Expand Up @@ -337,6 +357,51 @@ if [ "$SKIP_SERVER" = false ]; then
export ARTEMIS_IRIS_SECRETTOKEN="${IRIS_SECRET_TOKEN}"
fi

# Optional: start the deterministic mock LLM and enable Hyperion on the server.
# Hyperion enablement (artemis.hyperion.enabled=true) also makes management/info
# activeModuleFeatures include "hyperion", which the variant e2e suite probes to
# decide whether to run. The mock speaks the OpenAI Chat Completions API; Spring AI's
# OpenAI client points at it via spring.ai.openai.base-url (note the /v1 suffix — the
# SDK appends /chat/completions itself).
if [ "$RUN_HYPERION" = true ]; then
echo -e "${BLUE}Hyperion enabled (RUN_HYPERION=true): starting the mock LLM on port ${HYPERION_MOCK_LLM_PORT}...${NC}"
# Kill any stale listener on the mock's port from a previous attempt.
STALE_MOCK=$(lsof -nP -iTCP:"${HYPERION_MOCK_LLM_PORT}" -sTCP:LISTEN 2>/dev/null | awk 'NR>1 {print $2}' | sort -u)
for pid in $STALE_MOCK; do
echo -e "${YELLOW}Killing stale process on port ${HYPERION_MOCK_LLM_PORT} (PID $pid)...${NC}"
kill_tree "$pid"
done
MOCK_LLM_PORT="${HYPERION_MOCK_LLM_PORT}" python3 "$HYPERION_MOCK_LLM_SCRIPT" > "$LOCAL_DIR/hyperion-mock-llm.log" 2>&1 &
MOCK_LLM_PID=$!
echo "$MOCK_LLM_PID" > "$LOCAL_DIR/hyperion-mock-llm.pid"
# Wait for the mock to accept connections before the server boots against it.
MOCK_READY=false
for _ in $(seq 1 20); do
if curl -sf "http://localhost:${HYPERION_MOCK_LLM_PORT}/health" >/dev/null 2>&1; then
MOCK_READY=true
break
fi
sleep 0.5
done
if [ "$MOCK_READY" = true ]; then
echo -e "${GREEN}Mock LLM is listening (PID $MOCK_LLM_PID).${NC}"
else
# Continuing would enable Hyperion and point Spring AI at a dead port, so the variant suite would
# fail later with connection errors that say nothing about the real cause.
echo -e "${RED}ERROR: mock LLM did not become ready; aborting instead of running Hyperion against a dead endpoint.${NC}"
if kill -0 "$MOCK_LLM_PID" 2>/dev/null; then
kill_tree "$MOCK_LLM_PID"
fi
rm -f "$LOCAL_DIR/hyperion-mock-llm.pid"
exit 1
fi
Comment thread
coderabbitai[bot] marked this conversation as resolved.
export ARTEMIS_HYPERION_ENABLED="true"
export SPRING_AI_OPENAI_BASE_URL="http://localhost:${HYPERION_MOCK_LLM_PORT}/v1"
export SPRING_AI_OPENAI_API_KEY="dummy-key"
export SPRING_AI_OPENAI_MICROSOFT_FOUNDRY="false"
export SPRING_AI_OPENAI_CHAT_MODEL="mock-model"
fi

# Server environment variables
export SPRING_PROFILES_ACTIVE="artemis,scheduling,localvc,localci,buildagent,core,dev"
export SPRING_DATASOURCE_URL="jdbc:postgresql://localhost:5432/Artemis?sslmode=disable"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package de.tum.cit.aet.artemis.exercise.dto;

import java.io.Serializable;
import java.time.ZonedDateTime;

import jakarta.validation.constraints.NotBlank;
Expand All @@ -15,10 +16,14 @@
/**
* Payload for creating a new {@link ExerciseVariantGroup}. The owning course is taken from the request path, not the
* body, and is immutable afterwards.
*
* Serializable because it is embedded — via the variant-generation request's placement — in the Hazelcast-distributed
* {@code VariantJob} record.
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
public record CreateExerciseVariantGroupDTO(@NotBlank @Size(max = 255) String title, @Nullable @PositiveOrZero Double maxPoints, @Nullable ZonedDateTime releaseDate,
@Nullable ZonedDateTime startDate, @Nullable ZonedDateTime dueDate, @Nullable ZonedDateTime assessmentDueDate, @Nullable ZonedDateTime exampleSolutionPublicationDate) {
@Nullable ZonedDateTime startDate, @Nullable ZonedDateTime dueDate, @Nullable ZonedDateTime assessmentDueDate, @Nullable ZonedDateTime exampleSolutionPublicationDate)
implements Serializable {

/**
* Converts this DTO into a new, unsaved {@link ExerciseVariantGroup} entity.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@

import de.tum.cit.aet.artemis.core.exception.BadRequestAlertException;
import de.tum.cit.aet.artemis.core.service.messaging.InstanceMessageSendService;
import de.tum.cit.aet.artemis.course.domain.Course;
import de.tum.cit.aet.artemis.course.repository.CourseRepository;
import de.tum.cit.aet.artemis.exercise.domain.Exercise;
import de.tum.cit.aet.artemis.exercise.domain.ExerciseVariantGroup;
import de.tum.cit.aet.artemis.exercise.repository.ExerciseRepository;
Expand All @@ -34,10 +36,12 @@
import de.tum.cit.aet.artemis.text.domain.TextExercise;

/**
* Keeps an {@link ExerciseVariantGroup} and its members on one shared timeline: joining adopts the group's dates, editing
* the group pushes them onto every member. Programming members use a dedicated flow that also recomputes the build-and-test
* date and reschedules build/test jobs. Group edits run the same post-save work a member's own update endpoint would, so a
* group edit is never a weaker operation — see {@link #runPostTimelineUpdateSideEffects}.
* Creates and keeps an {@link ExerciseVariantGroup} and its members on one shared timeline. Group creation is shared by
* the {@link de.tum.cit.aet.artemis.exercise.web.ExerciseVariantGroupResource} and the AI variant-generation finalizer, so
* both place exercises into groups without duplicating the logic. Joining a group adopts its dates, and editing the
* group's dates pushes them onto every member. Programming members use a dedicated flow that also recomputes the
* build-and-test date and reschedules build/test jobs. Group edits run the same post-save work a member's own update
* endpoint would, so a group edit is never a weaker operation — see {@link #runPostTimelineUpdateSideEffects}.
*/
@Profile(PROFILE_CORE)
@Lazy
Expand All @@ -50,6 +54,8 @@ public class ExerciseVariantGroupService {

private final ExerciseRepository exerciseRepository;

private final CourseRepository courseRepository;

private final ProgrammingExerciseCreationUpdateService programmingExerciseCreationUpdateService;

private final ParticipationRepository participationRepository;
Expand All @@ -64,12 +70,13 @@ public class ExerciseVariantGroupService {

private final Optional<SlideApi> slideApi;

public ExerciseVariantGroupService(ExerciseVariantGroupRepository exerciseVariantGroupRepository, ExerciseRepository exerciseRepository,
public ExerciseVariantGroupService(ExerciseVariantGroupRepository exerciseVariantGroupRepository, ExerciseRepository exerciseRepository, CourseRepository courseRepository,
ProgrammingExerciseCreationUpdateService programmingExerciseCreationUpdateService, ParticipationRepository participationRepository, ExerciseService exerciseService,
ExerciseVersionService exerciseVersionService, InstanceMessageSendService instanceMessageSendService, QuizExerciseService quizExerciseService,
Optional<SlideApi> slideApi) {
this.exerciseVariantGroupRepository = exerciseVariantGroupRepository;
this.exerciseRepository = exerciseRepository;
this.courseRepository = courseRepository;
this.programmingExerciseCreationUpdateService = programmingExerciseCreationUpdateService;
this.participationRepository = participationRepository;
this.exerciseService = exerciseService;
Expand All @@ -79,6 +86,26 @@ public ExerciseVariantGroupService(ExerciseVariantGroupRepository exerciseVarian
this.slideApi = slideApi;
}

/**
* Creates a new variant group and attaches it to the given course.
*
* @param courseId the id of the course that will own the group
* @param group the new, unsaved group entity
* @return the persisted group
*/
public ExerciseVariantGroup createGroup(Long courseId, ExerciseVariantGroup group) {
group.validateDates();
// The course owns the unidirectional collection (the course_id FK lives on this table but is managed from the
// Course side). Persist the group first so it gets an id, then attach it so the course_id FK is written. Not
// wrapped in a transaction (this codebase avoids service-level @Transactional); validation runs before the
// first save, so a failure between the two can only leave an orphan, course-less group no course query sees.
group = exerciseVariantGroupRepository.save(group);
Course course = courseRepository.findWithEagerExerciseVariantGroupsByIdElseThrow(courseId);
course.addExerciseVariantGroup(group);
courseRepository.save(course);
return group;
}

/**
* Applies the group's timeline to every member and persists both. All members are validated before anything is saved
* (a timeline valid at group level can still be rejected by a member), so an invalid request mutates nothing.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,8 @@ public ExerciseVariantGroupResource(CourseRepository courseRepository, ExerciseV
public ResponseEntity<ExerciseVariantGroupDTO> createExerciseVariantGroup(@Valid @RequestBody CreateExerciseVariantGroupDTO createDTO, @PathVariable Long courseId)
throws URISyntaxException {
log.debug("REST request to create ExerciseVariantGroup in course {} : {}", courseId, createDTO);
ExerciseVariantGroup group = createDTO.toEntity();
group.validateDates();
// The course owns the unidirectional collection, so save the group first to get an id, then attach it to write the
// course_id FK. Not transactional (this codebase avoids service-level @Transactional); a failure between the two
// saves can only leave an orphan, course-less group that no course-scoped query ever sees.
group = exerciseVariantGroupRepository.save(group);
Course course = courseRepository.findWithEagerExerciseVariantGroupsByIdElseThrow(courseId);
course.addExerciseVariantGroup(group);
courseRepository.save(course);
// Group creation and course attachment live in the service, shared with the AI variant-generation finalizer.
ExerciseVariantGroup group = exerciseVariantGroupService.createGroup(courseId, createDTO.toEntity());
return ResponseEntity.created(new URI("/api/exercise/courses/" + courseId + "/exercise-variant-groups/" + group.getId())).body(new ExerciseVariantGroupDTO(group));
}

Expand Down
Loading
Loading