Skip to content

Adaptive learning: Replace string-based delegation markers with Spring AI tool calls#12373

Open
jaylann wants to merge 35 commits intodevelopfrom
feature/atlas/tool-based-agent-delegation
Open

Adaptive learning: Replace string-based delegation markers with Spring AI tool calls#12373
jaylann wants to merge 35 commits intodevelopfrom
feature/atlas/tool-based-agent-delegation

Conversation

@jaylann
Copy link
Copy Markdown
Contributor

@jaylann jaylann commented Mar 27, 2026

Summary

Replace the string-based delegation markers in the Atlas Agent orchestrator with Spring AI tool-based programmatic routing, and replace marker-based preview data embedding with Hazelcast cache-backed preview history. The main agent now delegates to sub-agents (Competency Expert, Competency Mapper, Exercise Mapper) via @Tool methods instead of embedding %%ARTEMIS_DELEGATE_TO_*%% text markers in LLM output. Preview data (competency, relation, exercise mapping) is now stored in a dedicated Hazelcast cache keyed by assistant message index instead of being serialized as %%PREVIEW_DATA_START%%/%%PREVIEW_DATA_END%% JSON markers in chat memory text. This eliminates all fragile string parsing, enables multi-delegation per request, produces cleaner conversation history, and aligns with Spring AI's native tool calling framework.

Checklist

General

Server

  • Important: I implemented the changes with a very good performance and prevented too many (unnecessary) and too complex database calls.
  • I strictly followed the principle of data economy for all database calls.
  • I strictly followed the server coding and design guidelines and the REST API guidelines.
  • I added multiple integration tests (Spring) related to the features (with a high test coverage).
  • I documented the Java code using JavaDoc style.

Motivation and Context

The Atlas Agent's multi-agent orchestration relied on text markers embedded in LLM output for two purposes: (1) delegation routing via %%ARTEMIS_DELEGATE_TO_*%% markers, and (2) preview data persistence via %%PREVIEW_DATA_START%%/%%PREVIEW_DATA_END%% markers serialized into chat memory.

Delegation markers had several problems:

  • Fragile string parsing: The 37-line extractBriefFromDelegationMarker() method was sensitive to LLM formatting variations (extra whitespace, missing colons, partial markers).
  • Single-delegation limitation: The if/else chain could only process one marker per request.
  • Prompt engineering burden: ~60 lines of the 724-line system prompt were dedicated to explaining the exact marker syntax.
  • Chat memory pollution: Marker-containing responses were saved to conversation history.

Preview data markers had similar issues:

  • Complex serialization: Three separate embed*InResponse() methods serialized DTOs as JSON wrapped in %%PREVIEW_DATA%% markers appended to message text.
  • Fragile extraction: extractPreviewDataFromMessage() used indexOf()/substring() parsing to recover the JSON, with type-sniffing via JsonNode.has() to distinguish competency vs. relation vs. exercise previews.
  • Memory mutation: updateChatMemoryWithEmbeddedData() had to clear and re-add all messages to splice embedded data into the last assistant message.
  • History coupling: getConversationHistoryAsDTO() had to extract and strip markers from every assistant message on every history load.

Spring AI 1.1.3 provides native tool calling for delegation, and Hazelcast provides a natural cache layer for preview persistence — both eliminate the need for text-based markers entirely.

Description

AtlasAgentToolsService.java (delegation):

  • 3 @Tool delegation methods: delegateToCompetencyExpert(), delegateToCompetencyMapper(), delegateToExerciseMapper()
  • Each tool reads courseId/sessionId from ThreadLocal, constructs the brief, calls delegateToAgent() with saveToMemory=false
  • Minor cleanup: removed unnecessary local variables (direct return statements)

AtlasAgentService.java (main simplification):

  • Replaced the 80-line delegation marker if/else chain with unified ThreadLocal preview collection
  • Deleted extractBriefFromDelegationMarker() and 4 marker constants
  • New: Preview data is now stored in AtlasAgentSessionCacheService keyed by assistant message index instead of being embedded as markers in chat memory
  • New: getConversationHistoryAsDTO() reconstructs previews from cache instead of parsing markers from message text
  • Replaced if/else chains in delegateToAgent() with switch expressions

AtlasAgentPreviewService.java (major reduction, -189 lines):

  • Removed all marker embed/extract methods: embedPreviewDataInResponse(), embedRelationPreviewDataInResponse(), embedExerciseMappingPreviewDataInResponse(), extractPreviewDataFromMessage(), updateChatMemoryWithEmbeddedData()
  • Removed all supporting records: PreviewDataContainer, RelationPreviewDataContainer, ExerciseMappingPreviewDataContainer, PreviewDataResult
  • Retained: convertToRelationPreviewsList(), addAssistantMessageToMemory()

AtlasAgentSessionCacheService.java (+69 lines):

  • Added MessagePreviewData record holding all preview types per message
  • Added storePreviewForMessage(), getPreviewHistory(), clearPreviewHistory() methods
  • New Hazelcast cache: atlas-session-preview-history

AtlasAgentChatResponseDTO.java:

  • Changed @JsonInclude from NON_EMPTY to NON_NULL (allows empty string messages while still omitting null fields)
  • Removed @NotBlank from message field (tool-only delegation responses may have null message)

AtlasAgentDelegationService.java:

  • Fixed config property prefix: atlas.chat-modelartemis.atlas.chat-model, atlas.chat-temperatureartemis.atlas.chat-temperature

CompetencyMappingToolsService.java:

  • Added zero-check for relation id (rel.id() == 0L) alongside null check to handle default long values

agent-chat-modal.component.ts:

  • Changed || to ?? for null coalescing on response messages (preserves empty strings)

HazelcastConfiguration.java:

  • Registered new atlas-session-preview-history map config

agent_system_prompt.st (rewritten):

  • Replaced "DELEGATION MARKERS" section with "DELEGATION TOOLS AND APPROVAL MARKERS" describing the 3 tool functions
  • Updated all 11 workflow examples to use tool call syntax instead of %%ARTEMIS_DELEGATE_TO_*%%: markers

AtlasAgentServiceTest.java (updated):

  • Removed 4 marker-based tests (multiple markers, empty brief, return-to-main, delegation marker in response)
  • Replaced with 3 new tests verifying unified preview collection and null-preview behavior
  • Updated 2 legacy-filtering tests to use inline string literals instead of deleted constants

AtlasAgentPreviewServiceTest.java (major reduction, -194 lines):

  • Removed all embed/extract marker tests (no longer applicable)
  • Retained relation preview conversion tests

AtlasAgentIntegrationTest.java (updated):

  • Preview history test now uses AtlasAgentSessionCacheService.storePreviewForMessage() instead of embedding markers in chat memory
  • Verifies cache-based preview retrieval in history endpoint

No changes to: sub-agent tool services (CompetencyExpertToolsService, CompetencyMappingToolsService, ExerciseMappingToolsService), sub-agent system prompts, approval flow (CREATE_APPROVED_* markers), plan execution system (ExecutionPlanStateManagerService).

Steps for Testing

Prerequisites:

  • 1 Instructor
  • 1 Course with existing competencies and exercises
  • Atlas Agent enabled (Azure OpenAI configured)
  1. Log in as Instructor
  2. Navigate to the course's Competency Management page
  3. Open the Atlas Agent chat

Test competency creation (delegateToCompetencyExpert):
4. Type "Create a competency about recursion"
5. Verify the agent delegates and shows a competency preview card (not a text description)
6. Type "Change the taxonomy to UNDERSTAND"
7. Verify the preview card updates
8. Type "Looks good, create it"
9. Verify the competency is created

Test relation mapping (delegateToCompetencyMapper):
10. Type "Make [Competency A] a prerequisite for [Competency B]" (using actual competency names)
11. Verify the agent delegates and shows a relation preview with graph visualization
12. Approve the relation

Test exercise mapping (delegateToExerciseMapper):
13. Type "Map exercises to competencies"
14. Verify the agent lists exercises and asks for selection
15. Select an exercise by number
16. Verify the exercise-competency mapping preview appears
17. Approve the mapping

Test non-delegation flow:
18. Type "What can you do?"
19. Verify the agent responds conversationally without delegating (no preview cards)

Test conversation history persistence:
20. After completing steps 4-9 (with preview cards visible), reload the page
21. Verify conversation history displays cleanly with preview cards restored from cache
22. Verify no internal markers or briefing text visible in history

Testserver States

You can manage test servers using Helios. Check environment statuses in the environment list. To deploy to a test server, go to the CI/CD page, find your PR or branch, and trigger the deployment.

Review Progress

Code Review

  • Code Review 1
  • Code Review 2

Manual Tests

  • Test 1
  • Test 2

Test Coverage

Client

Class/File Line Coverage Lines Expects Ratio
agent-chat-modal.component.ts 97.87% 443 221 49.9

Server

Class/File Line Coverage Lines
AtlasAgentToolConfig.java not found (deleted) ?
CompetencyGraphEdgeDTO.java 100.00% 13
CompetencyGraphNodeDTO.java 100.00% 16
CompetencyRelationDTO.java 100.00% 12
AtlasAgentChatResponseDTO.java 100.00% 12
CompetencyPreviewDTO.java 100.00% 7
CompetencyRelationPreviewDTO.java 100.00% 9
ExerciseCompetencyMappingDTO.java 100.00% 10
RelationGraphPreviewDTO.java 100.00% 10
AtlasAgentDelegationService.java 95.24% 52
AtlasAgentPreviewService.java 100.00% 38
AtlasAgentService.java 53.54% 484
AtlasAgentSessionCacheService.java 77.78% 126
AtlasAgentToolCallbackService.java 72.73% 37
AtlasAgentToolsService.java 75.00% 124
CompetencyMappingToolsService.java 68.75% 361
HazelcastConfiguration.java 63.16% 477

Last updated: 2026-04-16 11:17:16 UTC

Screenshots

No UI changes. The delegation mechanism is internal to the server; the frontend receives the same DTO structure (AtlasAgentChatResponseDTO) with identical fields.

Summary by CodeRabbit

  • Refactor

    • Delegation now uses explicit delegation tools/services; previews are stored in a per-session cache instead of embedded in assistant messages; UI preserves empty assistant messages.
  • Bug Fixes

    • Relation mapping treats zero IDs as new relations.
  • Chores

    • DTOs made serializable; session cache and cache configuration extended for preview history; response validation/serialization relaxed to allow empty messages.
  • Tests

    • Unit and integration tests updated and added to cover delegation and preview caching changes.

@jaylann jaylann self-assigned this Mar 27, 2026
@jaylann jaylann requested review from a team and krusche as code owners March 27, 2026 13:43
@jaylann jaylann added enhancement code quality refactoring atlas Pull requests that affect the corresponding module labels Mar 27, 2026
@github-project-automation github-project-automation bot moved this to Work In Progress in Artemis Development Mar 27, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1d91384e33

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsService.java Outdated
Comment thread src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentService.java Outdated
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Replaces marker-based delegation and embedded-preview plumbing with explicit tool-based delegation and a centralized delegation flow: adds delegation and tool-callback services, per-request ThreadLocal context and new @Tool delegation methods, moves preview storage to a session cache, updates prompts, DTOs, Hazelcast config, and tests.

Changes

Cohort / File(s) Summary
Removed Config
src/main/java/de/tum/cit/aet/artemis/atlas/config/AtlasAgentToolConfig.java
Deleted Spring @Configuration that registered qualified ToolCallbackProvider beans.
Core Agent Service
src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentService.java
Removed marker parsing and embedded-preview logic; now uses AtlasAgentDelegationService and AtlasAgentToolCallbackService, manages ThreadLocal request context, stores previews in session cache, refactored delegation internals, and adjusted visibility/constructor signature and helper methods.
Tools Service
src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsService.java
Added static ThreadLocal context setters/clearers; constructor now requires delegation & tool-callback services; added @Tool methods (delegateToCompetencyExpert, delegateToCompetencyMapper, delegateToExerciseMapper) that validate context, format briefs, set sub-agent session ID, and call delegation.
Delegation Service
src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentDelegationService.java
New lazy/conditional Spring service centralizing system-prompt rendering, ChatClient mutation, optional memory advisor, tool-callback attachment, chat invocation, and response extraction via delegateToAgent(...).
Tool Callback Factory
src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolCallbackService.java
New lazy/conditional Spring service building/caching MethodToolCallbackProvider instances for main and sub-agents and exposing factory methods.
Preview Cache
src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentSessionCacheService.java
Added atlas-session-preview-history cache constant, serializable MessagePreviewData record, and methods to store/get/clear per-session per-message preview data with null-guards for missing cache.
Preview Service
src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentPreviewService.java
Removed preview embedding/extraction subsystem, related DTO containers, JSON (ObjectMapper) usage, and public APIs for embedding/extracting/updating chat memory; retained relation-preview conversion and assistant-memory helper.
Prompts — Agent
src/main/resources/prompts/atlas/agent_system_prompt.st
Rewrote system prompt to instruct direct tool calls (delegateToCompetencyExpert/Mapper/ExerciseMapper) replacing delegation markers; updated examples, rules, and topic formatting guidance; adjusted decision tree for when to call tools.
Prompts — Competency/Mapper/Exercise
src/main/resources/prompts/atlas/competency_expert_system_prompt.st, .../competency_mapper_system_prompt.st, .../exercise_mapper_system_prompt.st
Removed legacy delegation placeholder lines and adjusted response/tool guidance and examples to match explicit tool usage; tuned workflow instructions.
Hazelcast Config
src/main/java/de/tum/cit/aet/artemis/core/config/HazelcastConfiguration.java
Registered new Hazelcast map atlas-session-preview-history using existing atlas session map config helper.
DTOs — Serializable
src/main/java/de/tum/cit/aet/artemis/atlas/dto/...
Multiple DTO records now implement Serializable: CompetencyGraphEdgeDTO, CompetencyGraphNodeDTO, CompetencyRelationDTO, CompetencyPreviewDTO, CompetencyRelationPreviewDTO, ExerciseCompetencyMappingDTO (and nested option), RelationGraphPreviewDTO.
Chat Response DTO
src/main/java/de/tum/cit/aet/artemis/atlas/dto/atlasAgent/AtlasAgentChatResponseDTO.java
Removed @NotBlank from message and changed Jackson inclusion from NON_EMPTY to NON_NULL (blank allowed; only nulls omitted).
Competency Mapping
src/main/java/de/tum/cit/aet/artemis/atlas/service/CompetencyMappingToolsService.java
saveRelationMappings(...) now treats id()==0L as unset and routes to create path rather than update.
Tools Tests
src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsServiceTest.java
New tests verifying ThreadLocal guards (JSON error when missing), brief formatting and correct delegateToAgent invocation (prompt path, brief, course/session), and pass-through behavior when delegation returns plain response.
Agent Service Tests
src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentServiceTest.java
Updated wiring for new constructor/delegation stack; adapted preview expectations to use session cache DTOs and removed marker-based assertions.
Integration Test
src/test/java/de/tum/cit/aet/artemis/atlas/agent/AtlasAgentIntegrationTest.java
Stubbed chatClient.mutate() to return ChatClient.builder(...); tests now pre-populate preview cache rather than embedding markers in assistant messages.
Preview Service Tests
src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentPreviewServiceTest.java
Removed tests exercising the removed embedding/extraction/chat-memory update behaviors and related imports/stubbing.
UI — Agent Chat Modal
src/main/webapp/app/atlas/manage/agent-chat-modal/*
Treat empty assistant messages as valid (use ?? fallback) and removed detection of delegation briefs prefixed with %%ARTEMIS_DELEGATE_TO_; pass through additional preview fields on plan approval.
Misc Tests/Adjustments
src/test/...
Updated tests to reflect preview caching and new delegation flow; added AtlasAgentToolsServiceTest, modified AtlasAgentServiceTest and integration tests accordingly.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant AtlasAgent as AtlasAgentService
    participant Tools as AtlasAgentToolsService
    participant ToolFactory as AtlasAgentToolCallbackService
    participant Delegation as AtlasAgentDelegationService
    participant SubAgent as Sub-Agent Model
    participant Cache as AtlasAgentSessionCacheService

    User->>AtlasAgent: processChatMessage(input)
    AtlasAgent->>Tools: set ThreadLocal courseId/sessionId
    AtlasAgent->>Delegation: delegateToAgent(systemPromptPath, userMsg, courseId, sessionId, saveToMemory?, provider?)
    Delegation->>ToolFactory: request ToolCallbackProvider
    ToolFactory-->>Delegation: ToolCallbackProvider
    Delegation->>SubAgent: invoke chat model (system + user + tools)
    SubAgent-->>Delegation: response (may call tools)
    SubAgent->>Tools: invoke tool (e.g., delegateToCompetencyExpert(...))
    Tools->>Tools: read ThreadLocal courseId/sessionId
    Tools->>Delegation: delegateToAgent(subPromptPath, brief, courseId, sessionId, false, subProvider)
    Delegation->>SubAgent: run sub-agent prompt
    SubAgent-->>Delegation: sub-agent response
    Delegation-->>Tools: delegated result
    Delegation-->>AtlasAgent: final response
    AtlasAgent->>Cache: store/read previews by assistant message index
    AtlasAgent->>Tools: clear ThreadLocal courseId/sessionId
    AtlasAgent-->>User: final response (previews populated from cache)
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: replacing string-based delegation markers with Spring AI tool calls, which is the core refactoring across the Atlas Agent codebase.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/atlas/tool-based-agent-delegation

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsServiceTest.java (1)

102-130: Consider adding test for delegateToCompetencyMapper brief formatting.

The DelegationBriefFormatting nested class tests brief construction for delegateToCompetencyExpert and delegateToExerciseMapper, but delegateToCompetencyMapper is missing. While it uses the same formatBrief helper, having explicit coverage ensures the correct agent type and parameters are passed.

📝 Suggested test addition
`@Test`
void shouldFormatCompetencyMapperBriefCorrectly() {
    when(atlasAgentService.delegateToAgent(any(), anyString(), anyLong(), anyString(), anyBoolean())).thenReturn("ok");

    toolsService.delegateToCompetencyMapper("A extends B", "Create EXTENDS relation", "None", "A builds on B");

    verify(atlasAgentService).delegateToAgent(eq(AtlasAgentService.AgentType.COMPETENCY_MAPPER),
            eq("TOPIC: A extends B\nREQUIREMENTS: Create EXTENDS relation\nCONSTRAINTS: None\nCONTEXT: A builds on B"), eq(42L), eq("test-session"), eq(false));
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsServiceTest.java`
around lines 102 - 130, Add a missing unit test to DelegationBriefFormatting
that verifies toolsService.delegateToCompetencyMapper builds and forwards the
correct brief and agent type; specifically, mock
atlasAgentService.delegateToAgent to return "ok", call
toolsService.delegateToCompetencyMapper(...) with sample inputs, and verify
atlasAgentService.delegateToAgent was called with
AtlasAgentService.AgentType.COMPETENCY_MAPPER, the expected formatted brief
string (matching formatBrief output), the current course/session via
AtlasAgentToolsService.getCurrentCourseId()/getCurrentSessionId() (set in
setThreadLocals), and false for the final boolean.
src/main/resources/prompts/atlas/agent_system_prompt.st (1)

106-109: Clarify instruction on exclusive tool call vs text output.

Lines 108-109 instruct the agent to "call the tool directly - do NOT output any additional text" and "NEVER output both a plan description AND a tool call together". This is important for consistent behavior, but Spring AI's tool calling typically allows the model to provide both text and tool calls in the same turn. Verify that your downstream processing correctly handles or strips any accompanying text when tool calls are present.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/resources/prompts/atlas/agent_system_prompt.st` around lines 106 -
109, The prompt rule for delegateToCompetencyExpert forbids any accompanying
text when calling the tool, but downstream Spring AI tooling can return both
text and tool calls; update either the prompt or runtime: (A) clarify or relax
the prompt text around delegateToCompetencyExpert to allow accompanying
explanatory text if your runtime supports it, or (B) enforce the existing rule
by changing the agent runtime that handles deployToolCalls to strip/ignore any
non-tool text when a delegateToCompetencyExpert tool call is present; locate the
delegateToCompetencyExpert guidance in the agent_system_prompt (symbol:
delegateToCompetencyExpert) and adjust the prompt wording or the tool-calling
handler (the component that processes tool calls) accordingly so behavior is
deterministic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/main/resources/prompts/atlas/agent_system_prompt.st`:
- Around line 106-109: The prompt rule for delegateToCompetencyExpert forbids
any accompanying text when calling the tool, but downstream Spring AI tooling
can return both text and tool calls; update either the prompt or runtime: (A)
clarify or relax the prompt text around delegateToCompetencyExpert to allow
accompanying explanatory text if your runtime supports it, or (B) enforce the
existing rule by changing the agent runtime that handles deployToolCalls to
strip/ignore any non-tool text when a delegateToCompetencyExpert tool call is
present; locate the delegateToCompetencyExpert guidance in the
agent_system_prompt (symbol: delegateToCompetencyExpert) and adjust the prompt
wording or the tool-calling handler (the component that processes tool calls)
accordingly so behavior is deterministic.

In
`@src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsServiceTest.java`:
- Around line 102-130: Add a missing unit test to DelegationBriefFormatting that
verifies toolsService.delegateToCompetencyMapper builds and forwards the correct
brief and agent type; specifically, mock atlasAgentService.delegateToAgent to
return "ok", call toolsService.delegateToCompetencyMapper(...) with sample
inputs, and verify atlasAgentService.delegateToAgent was called with
AtlasAgentService.AgentType.COMPETENCY_MAPPER, the expected formatted brief
string (matching formatBrief output), the current course/session via
AtlasAgentToolsService.getCurrentCourseId()/getCurrentSessionId() (set in
setThreadLocals), and false for the final boolean.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 56d25dfb-2b70-4426-8393-df51d722a427

📥 Commits

Reviewing files that changed from the base of the PR and between ac14357 and 1d91384.

📒 Files selected for processing (6)
  • src/main/java/de/tum/cit/aet/artemis/atlas/config/AtlasAgentToolConfig.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentService.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsService.java
  • src/main/resources/prompts/atlas/agent_system_prompt.st
  • src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentServiceTest.java
  • src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsServiceTest.java

coderabbitai[bot]
coderabbitai bot previously approved these changes Mar 27, 2026
@github-actions github-actions bot added tests server Pull requests that update Java code. (Added Automatically!) labels Mar 27, 2026
@github-actions
Copy link
Copy Markdown

@jaylann Test coverage could not be fully measured because some tests failed. Please check the workflow logs for details.

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 27, 2026

End-to-End Test Results

Phase Status Details
All Tests ❌ Failed
TestsPassed ☑️Skipped ⚠️Failed ❌️Time ⏱
All E2E Tests Report (PR)253 ran250 passed2 skipped1 failed30m 28s

Test Strategy: Running all tests (configuration or infrastructure changes detected)

Overall: ❌ E2E tests failed

🔗 Workflow Run · 📊 Test Report

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentDelegationService.java (1)

63-70: Potential null return from getSubAgentToolCallbackProvider.

The method can return null if a ToolCallbackProvider wasn't configured. While delegateToAgent handles null toolCallbackProvider gracefully (line 112-114), callers should be aware this can happen when the corresponding tools service isn't available.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentDelegationService.java`
around lines 63 - 70, The getSubAgentToolCallbackProvider method can return null
when a ToolCallbackProvider wasn't configured; change its signature to return
Optional<ToolCallbackProvider> and return Optional.ofNullable(...) for
competencyExpertToolCallbackProvider, competencyMapperToolCallbackProvider and
exerciseMapperToolCallbackProvider (keep the IllegalArgumentException for
MAIN_AGENT). Update callers (notably delegateToAgent) to accept Optional by
calling isPresent()/orElseThrow()/ifPresent() or map() as appropriate so null is
no longer propagated silently.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentDelegationService.java`:
- Around line 97-117: The method delegateToAgent currently returns the result of
promptSpec.call().content() which is annotated `@Nullable`; add explicit null
handling by capturing promptSpec.call().content() into a local variable, check
for null, and handle it (e.g., throw an IllegalStateException with context
including sessionId/courseId and the promptResourcePath or alternatively return
null and annotate the delegateToAgent method with `@Nullable`); update callers if
you choose the `@Nullable` route. Ensure you reference delegateToAgent and the
promptSpec.call().content() call when making the change so the null
check/annotation is applied to the correct return path.

---

Nitpick comments:
In
`@src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentDelegationService.java`:
- Around line 63-70: The getSubAgentToolCallbackProvider method can return null
when a ToolCallbackProvider wasn't configured; change its signature to return
Optional<ToolCallbackProvider> and return Optional.ofNullable(...) for
competencyExpertToolCallbackProvider, competencyMapperToolCallbackProvider and
exerciseMapperToolCallbackProvider (keep the IllegalArgumentException for
MAIN_AGENT). Update callers (notably delegateToAgent) to accept Optional by
calling isPresent()/orElseThrow()/ifPresent() or map() as appropriate so null is
no longer propagated silently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 79ab3a26-ee21-4b1d-8d87-bead4b9c2fe0

📥 Commits

Reviewing files that changed from the base of the PR and between 1d91384 and f48fd05.

📒 Files selected for processing (5)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentDelegationService.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentService.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsService.java
  • src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentServiceTest.java
  • src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsServiceTest.java
✅ Files skipped from review due to trivial changes (1)
  • src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsServiceTest.java

@github-project-automation github-project-automation bot moved this from Work In Progress to Ready For Review in Artemis Development Mar 27, 2026
@github-actions
Copy link
Copy Markdown

@jaylann Test coverage has been automatically updated in the PR description.

@jaylann jaylann moved this from Ready For Review to Work In Progress in Artemis Development Mar 27, 2026
@jaylann jaylann added this to Atlas Mar 27, 2026
@jaylann jaylann moved this to In progress in Atlas Mar 27, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentService.java (1)

144-145: Comment is slightly misleading — tool calls happen during, not after, this invocation.

The comment says "delegation to sub-agents happens via tool calls inside this invocation" but then the code calls delegateToAgent(AgentType.MAIN_AGENT, ...). The tool-based delegation occurs during the AI model's execution when it decides to call delegation tools, not explicitly here. Consider clarifying that the main agent may internally invoke delegation tools during its response generation.

✏️ Suggested comment clarification
-            // Single main agent call — delegation to sub-agents happens via tool calls inside this invocation
+            // Call main agent — it may invoke delegation tools (delegateToCompetencyExpert, etc.) during response generation
             String response = delegateToAgent(AgentType.MAIN_AGENT, message, courseId, sessionId);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentService.java`
around lines 144 - 145, Update the misleading comment above the delegateToAgent
call: clarify that calling delegateToAgent(AgentType.MAIN_AGENT, message,
courseId, sessionId) invokes the main agent, and that any delegation to
sub-agents happens internally during the main agent's execution via tool calls
invoked by the model (not as a separate call after delegateToAgent returns);
reference delegateToAgent and AgentType.MAIN_AGENT in the comment so readers
know the main agent may trigger tool-based delegation while generating its
response.
src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentServiceTest.java (1)

158-160: Consider extracting repeated deployment configuration to constants.

The values "gpt-4o" and 0.2 are duplicated across multiple test instantiations of AtlasAgentDelegationService. Extracting these to constants would reduce duplication and make it easier to update if these values change.

♻️ Suggested refactor

Add constants at the class level:

private static final String TEST_DEPLOYMENT_NAME = "gpt-4o";
private static final double TEST_TEMPERATURE = 0.2;

Then replace usages:

-new AtlasAgentDelegationService(ChatClient.create(chatModel), templateService, null, "gpt-4o", 0.2)
+new AtlasAgentDelegationService(ChatClient.create(chatModel), templateService, null, TEST_DEPLOYMENT_NAME, TEST_TEMPERATURE)

Also applies to: 261-263, 643-644, 664-665, 671-673

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentServiceTest.java`
around lines 158 - 160, Several tests repeatedly inline the deployment name
"gpt-4o" and temperature 0.2 when constructing AtlasAgentDelegationService
instances (e.g., in the AtlasAgentService test creating AtlasAgentService and
AtlasAgentDelegationService); extract these literals into class-level constants
(e.g., private static final String TEST_DEPLOYMENT_NAME = "gpt-4o"; private
static final double TEST_TEMPERATURE = 0.2) and replace all occurrences used in
AtlasAgentDelegationService constructor calls (and any other test
instantiations) with TEST_DEPLOYMENT_NAME and TEST_TEMPERATURE to remove
duplication and centralize configuration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentDelegationService.java`:
- Around line 60-81: The method delegateToAgent calls chatClient.mutate()
without verifying chatClient isn't null; add a null-safety check at the start of
delegateToAgent (or before calling chatClient.mutate()) to handle the nullable
ChatClient: if chatClient is null, either throw a clear IllegalStateException
(or return an appropriate error) with a descriptive message like "ChatClient not
configured" so callers see the problem, otherwise proceed to call
chatClient.mutate() and build sessionClient as before.

---

Nitpick comments:
In `@src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentService.java`:
- Around line 144-145: Update the misleading comment above the delegateToAgent
call: clarify that calling delegateToAgent(AgentType.MAIN_AGENT, message,
courseId, sessionId) invokes the main agent, and that any delegation to
sub-agents happens internally during the main agent's execution via tool calls
invoked by the model (not as a separate call after delegateToAgent returns);
reference delegateToAgent and AgentType.MAIN_AGENT in the comment so readers
know the main agent may trigger tool-based delegation while generating its
response.

In
`@src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentServiceTest.java`:
- Around line 158-160: Several tests repeatedly inline the deployment name
"gpt-4o" and temperature 0.2 when constructing AtlasAgentDelegationService
instances (e.g., in the AtlasAgentService test creating AtlasAgentService and
AtlasAgentDelegationService); extract these literals into class-level constants
(e.g., private static final String TEST_DEPLOYMENT_NAME = "gpt-4o"; private
static final double TEST_TEMPERATURE = 0.2) and replace all occurrences used in
AtlasAgentDelegationService constructor calls (and any other test
instantiations) with TEST_DEPLOYMENT_NAME and TEST_TEMPERATURE to remove
duplication and centralize configuration.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b3898216-7491-4b8b-9a9f-43f654769400

📥 Commits

Reviewing files that changed from the base of the PR and between f48fd05 and 28b1fae.

📒 Files selected for processing (5)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentDelegationService.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentService.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsService.java
  • src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentServiceTest.java
  • src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsServiceTest.java
✅ Files skipped from review due to trivial changes (1)
  • src/test/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsServiceTest.java
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentToolsService.java

@github-project-automation github-project-automation bot moved this from Work In Progress to Ready For Review in Artemis Development Mar 27, 2026
@github-actions github-actions bot added the config-change Pull requests that change the config in a way that they require a deployment via Ansible. label Apr 13, 2026
Copy link
Copy Markdown
Contributor

@Claudia-Anthropica Claudia-Anthropica left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jaylann Clean refactoring — replacing the fragile marker-based delegation with Spring AI tool calls and moving preview persistence to Hazelcast cache is a solid architectural improvement. One config issue inline: the temperature property key doesn't match the YAML, so the config value is silently ignored.

@github-actions
Copy link
Copy Markdown

@jaylann Test coverage has been automatically updated in the PR description.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentDelegationService.java`:
- Around line 70-72: The code configures MessageChatMemoryAdvisor when
saveToMemory is true without validating sessionId, which can merge distinct
conversations; update the block that calls clientBuilder.defaultAdvisors(...) to
first check that sessionId is non-null and non-blank (e.g. use sessionId != null
&& !sessionId.isBlank() or a StringUtils.hasText check) and only build and set
MessageChatMemoryAdvisor.builder(chatMemory).conversationId(sessionId).build()
when the sessionId passes that validation; if invalid, skip configuring the
advisor (and optionally log a warning).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: ae1250fc-62e6-41be-ae1c-39ff08963a14

📥 Commits

Reviewing files that changed from the base of the PR and between 0523f0f and 439665d.

⛔ Files ignored due to path filters (1)
  • src/main/resources/config/application-artemis.yml is excluded by !**/*.yml
📒 Files selected for processing (3)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentDelegationService.java
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentService.java
  • src/main/resources/prompts/atlas/exercise_mapper_system_prompt.st
✅ Files skipped from review due to trivial changes (1)
  • src/main/resources/prompts/atlas/exercise_mapper_system_prompt.st
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/java/de/tum/cit/aet/artemis/atlas/service/AtlasAgentService.java

Copy link
Copy Markdown
Contributor

@Claudia-Anthropica Claudia-Anthropica left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jaylann Clean refactoring — replacing the fragile marker-based delegation with Spring AI tool calls and moving preview persistence to Hazelcast cache is a solid architectural improvement. All previous feedback addressed (temperature config fix, spotless formatting, provider caching, sub-agent prompt cleanup, exerciseId passthrough). Nice work.

@github-actions
Copy link
Copy Markdown

@jaylann Test coverage has been automatically updated in the PR description.

@github-actions
Copy link
Copy Markdown

@jaylann Test coverage has been automatically updated in the PR description.

coderabbitai[bot]
coderabbitai bot previously approved these changes Apr 13, 2026
Copy link
Copy Markdown
Contributor

@MarkusPaulsen MarkusPaulsen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested on TS2.

Before entering "Change the taxonomy to UNDERSTAND", I got the competency preview card:

Recursive Problem Solving
Apply recursion to solve algorithmic problems
Identify base and recursive cases
Implement recursive solutions correctly

After entering "Change the taxonomy to UNDERSTAND", I got the competency preview card:

Recursive Problem Solving
Apply recursion to solve algorithmic problems
Identify base and recursive cases
Implement recursive solutions correctly

So there was no textual change.

Image

@github-actions
Copy link
Copy Markdown

@jaylann Test coverage has been automatically updated in the PR description.

@jaylann
Copy link
Copy Markdown
Contributor Author

jaylann commented Apr 14, 2026

Tested on TS2.

Before entering "Change the taxonomy to UNDERSTAND", I got the competency preview card:

Recursive Problem Solving
Apply recursion to solve algorithmic problems
Identify base and recursive cases
Implement recursive solutions correctly

After entering "Change the taxonomy to UNDERSTAND", I got the competency preview card:

Recursive Problem Solving
Apply recursion to solve algorithmic problems
Identify base and recursive cases
Implement recursive solutions correctly

So there was no textual change.
Image

This is preexisting behavior caused by the prompt. A large prompt refactoring is out of scope for this PR but will be addressed in a followup

@jaylann jaylann requested a review from MarkusPaulsen April 14, 2026 09:13
Comment thread src/main/resources/config/application-artemis.yml
@github-actions
Copy link
Copy Markdown

@jaylann Test coverage has been automatically updated in the PR description.

Copy link
Copy Markdown
Contributor

@Claudia-Anthropica Claudia-Anthropica left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jaylann Clean refactoring — the migration from string-based delegation markers to Spring AI tool calls is solid, and the Hazelcast-backed preview cache is well-designed. The per-session locking in storePreviewForMessage properly prevents the read-modify-write race, and the concurrency test is a nice addition. All previous feedback addressed, nice work.

Copy link
Copy Markdown
Contributor

@Claudia-Anthropica Claudia-Anthropica left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jaylann Clean refactoring — the migration from string-based delegation markers to Spring AI tool calls is well-executed, and the Hazelcast-backed preview cache is a solid replacement for the fragile marker embedding approach. All previous feedback addressed (spotless formatting, provider caching, config property alignment, prompt cleanup, per-session locking, ?? coalescing tests). Nice work.

@github-actions
Copy link
Copy Markdown

@jaylann Test coverage has been automatically updated in the PR description.

Copy link
Copy Markdown
Contributor

@alretum alretum left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested locally and everything works as described

Copy link
Copy Markdown
Contributor

@louis-heinrich louis-heinrich left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM. Tested locally and worked as expected.

Copy link
Copy Markdown
Contributor

@MarcosOlivaKaczmarek MarcosOlivaKaczmarek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

atlas Pull requests that affect the corresponding module client Pull requests that update TypeScript code. (Added Automatically!) code quality config-change Pull requests that change the config in a way that they require a deployment via Ansible. core Pull requests that affect the corresponding module enhancement ready to merge refactoring server Pull requests that update Java code. (Added Automatically!) tests

Projects

Status: Ready For Review
Status: In progress

Development

Successfully merging this pull request may close these issues.

6 participants