removed open tasks

This commit is contained in:
Konrad Neitzel 2026-02-21 12:45:39 +01:00
parent b79334ee67
commit cf93b35dd6

View File

@ -1,155 +0,0 @@
# Plan: Open Tasks (Ollama Integration in InMemorySessionService)
This document plans the two remaining backend open tasks: wiring the two-call Ollama pattern into **createSession** and **submitTurn** in [InMemorySessionService](src/main/java/de/neitzel/roleplay/business/InMemorySessionService.java).
---
## Overview
| Task | Method | Goal |
|------|--------|------|
| 1 | `createSession` | Produce opening narrative and initial state via Ollama (narrative + state extraction). |
| 2 | `submitTurn` | Produce turn narrative and state update via Ollama (narrative + state update), then merge into session. |
Both follow the same pattern: build **TurnContext** (JSON) → **Call 1** (narrative) → **Call 2** (state update with narrative in user message) → map **StateUpdateResponse** and narrative into API responses and session state.
---
## Prerequisites and Dependencies
- **[OllamaClient](src/main/java/de/neitzel/roleplay/fascade/OllamaClient.java)** already provides `generateNarrative(model, systemPrompt, userContent)` and `generateStateUpdate(model, systemPrompt, userContent)`.
- **Common types** ([common](src/main/java/de/neitzel/roleplay/common/)) `TurnContext`, `StateUpdateResponse`, `SituationSnapshot`, `CharacterSet`, `CharacterSnapshot`, `UserAction`, `Recommendation`, `SituationUpdate`, `CharacterUpdate`, `OpenThreadsChanges`, `CharacterResponse`, `Suggestion` (with `SuggestionType`, `RiskLevel`).
- **API models** (`de.neitzel.roleplay.fascade.model`) generated from OpenAPI: `SessionResponse`, `TurnResponse`, `SituationState`, `CharacterState`, `Suggestion`, `CharacterResponseItem`, etc.
- **Prompts** defined in [ROLEPLAY_CONCEPT.md](docs/ROLEPLAY_CONCEPT.md) (§4.3 for init, §4.4 for turn). Should be extracted to constants or a small prompt provider (e.g. in `business` or `common`) so they stay consistent and maintainable.
---
## Task 1: createSession Opening scene and initial state
### Flow
1. Create `SessionResponse` with sessionId, model, language, safetyLevel, turnNumber (0) **unchanged**.
2. Build initial **situation** and **characters** from `request.getScenario()` (reuse existing `buildSituationFromScenario` / `buildCharactersFromScenario`).
3. Build **TurnContext** for session init:
- **currentSituation**: Map from `SituationState` (API) to `SituationSnapshot` (common). Initial values: setting, currentScene from scenario; timeline/openThreads/externalPressures/worldStateFlags can be empty or minimal.
- **characters**: Map from `CharacterState` list to `CharacterSet` (userCharacter + aiCharacters). Map each to `CharacterSnapshot` (id, name, role, personalityTraits, speakingStyle, goals from scenario; currentMood/status/knowledge/relationships/recentActionsSummary can be null or default).
- **userAction**: `null` (no user action at init).
- **recommendation**: `null`.
- **recentHistorySummary**: `null` or `""`.
4. Serialise `TurnContext` to JSON (snake_case) via Jackson `ObjectMapper`.
5. **Call 1** `ollamaClient.generateNarrative(model, INIT_SYSTEM_PROMPT, contextJson)`.
6. **Call 2** `ollamaClient.generateStateUpdate(model, STATE_EXTRACT_SYSTEM_PROMPT, contextJson + "\n\nNarrative that was just generated:\n" + narrative)`.
7. Set **session** from Call 1 + Call 2:
- `session.setNarrative(narrative)` (from Call 1).
- Apply **StateUpdateResponse** to session:
- **updated_situation** → merge into `session.getSituation()` (or build new `SituationState`): currentScene, append newTimelineEntries to timeline, apply openThreadsChanges (add/remove from openThreads), set worldStateFlags.
- **updated_characters** → merge into `session.getCharacters()` by characterId: update currentMood, append knowledgeGained to knowledge, apply relationshipChanges to relationships; keep id/name/role/isUserCharacter from existing list.
- **suggestions** → map common `Suggestion` list to API `Suggestion` list and `session.setSuggestions(...)`.
8. Store session and return.
### Design choices
- **Context builder**: Introduce a small helper (or service) to build `TurnContext` from scenario + optional session state, and to serialise it. Keeps `InMemorySessionService` focused on orchestration.
- **Situation/character mapping**: Reuse or introduce mappers between API models (`SituationState`, `CharacterState`) and common types (`SituationSnapshot`, `CharacterSnapshot`) so both createSession and submitTurn can share the same logic.
- **Error handling**: If Ollama fails (network, parse), decide: throw and fail session creation, or fall back to placeholder narrative and log. Prefer throwing and letting the resource layer return 5xx, with a clear message.
---
## Task 2: submitTurn Turn narrative and state update
### Flow
1. Load session; if missing return `Optional.empty()` **unchanged**.
2. Increment turn number **unchanged**.
3. Build **TurnContext** for this turn:
- **currentSituation**: From `session.getSituation()``SituationSnapshot` (setting, currentScene, timeline, openThreads, externalPressures, worldStateFlags).
- **characters**: From `session.getCharacters()``CharacterSet` (userCharacter + aiCharacters as `CharacterSnapshot` list).
- **userAction**: From `turnRequest.getUserAction()` → map API `UserActionRequest` to common `UserAction` (type, content, selectedSuggestionId).
- **recommendation**: From `turnRequest.getRecommendation()` → map to common `Recommendation` (desiredTone, preferredDirection, focusCharacters), or null.
- **recentHistorySummary**: For now empty string or a short placeholder; later can be derived from stored turn history if added.
4. Serialise `TurnContext` to JSON.
5. **Call 1** `ollamaClient.generateNarrative(model, TURN_NARRATIVE_SYSTEM_PROMPT, contextJson)`.
6. **Call 2** `ollamaClient.generateStateUpdate(model, STATE_EXTRACT_SYSTEM_PROMPT, contextJson + "\n\nNarrative that was just generated:\n" + narrative)`.
7. Build **TurnResponse**:
- turnNumber, narrative (from Call 1).
- characterResponses, updatedSituation, updatedCharacters, suggestions from `StateUpdateResponse` (mapped to API model types).
8. **Merge** state update into session (same as createSession): apply updated_situation to `session.getSituation()`, updated_characters to `session.getCharacters()`, replace `session.setSuggestions(...)`, set `session.setNarrative(narrative)`, `session.setTurnNumber(nextTurn)`.
9. Save session and return `Optional.of(turnResponse)`.
### Design choices
- **Shared merge logic**: Extract “apply StateUpdateResponse to SessionResponse” into a private method (or small helper) used by both createSession and submitTurn.
- **TurnResponse mapping**: Map `StateUpdateResponse` (common) to `TurnResponse` (API): responses → characterResponses, updatedSituation, updatedCharacters, suggestions. API uses same structure; ensure enum/value names match (e.g. speech/action/reaction, risk_level).
---
## Shared implementation elements
### 1. Prompts
- **INIT_SYSTEM_PROMPT** (opening narrative) from concept §4.3 Call 1.
- **STATE_EXTRACT_SYSTEM_PROMPT** (JSON extraction) from concept §4.3 Call 2 (same for init and turn).
- **TURN_NARRATIVE_SYSTEM_PROMPT** (turn continuation) from concept §4.4 Call 1.
Store as constants in a single class (e.g. `OllamaPrompts` in `business`) or in a configurable provider.
### 2. Context building
- **Session init**: `TurnContext` from scenario-derived situation + characters; no userAction/recommendation.
- **Turn**: `TurnContext` from current session situation + characters + userAction + recommendation.
Both need **API → common** mapping for situation and characters when building the context. A dedicated mapper or builder class keeps the service clean.
### 3. State merge (StateUpdateResponse → SessionResponse)
- **Situation**: Apply `SituationUpdate`: set currentScene if present; append newTimelineEntries to timeline; apply openThreadsChanges (add/remove from openThreads); replace or merge worldStateFlags.
- **Characters**: For each `CharacterUpdate` find character by characterId; update currentMood; append knowledgeGained to knowledge; merge relationshipChanges into relationships.
- **Suggestions**: Replace session suggestions with the new list (mapped from common to API).
### 4. API ↔ common mapping
- **Common** uses snake_case (Jackson `@JsonNaming`); **API** models are OpenAPI-generated (camelCase). When mapping StateUpdateResponse (common) into SessionResponse / TurnResponse (API), copy fields and convert enums where needed (e.g. ResponseType, SuggestionType, RiskLevel).
- **TurnContext** is always built from common types and serialised to JSON as-is for Ollama.
---
## Suggested order of implementation
1. **Prompts** Add `OllamaPrompts` (or similar) with the three system prompt strings from the concept doc.
2. **Mappers** Add mapping from API `SituationState`/`CharacterState` (and scenario) to common `SituationSnapshot`/`CharacterSet`/`CharacterSnapshot`; and from common `StateUpdateResponse`/`Suggestion`/etc. to API types for SessionResponse/TurnResponse. Optionally a dedicated “context builder” that takes scenario or session + turnRequest and returns `TurnContext`.
3. **State merge** Implement “apply StateUpdateResponse to SessionResponse” (situation, characters, suggestions) in one place.
4. **createSession** Inject `OllamaClient` and `ObjectMapper`; build context from scenario; call two-step Ollama; merge state; set narrative/situation/characters/suggestions on session.
5. **submitTurn** Build context from session + turnRequest; call two-step Ollama; build TurnResponse; merge state into session; return TurnResponse.
6. **Tests** Update or add unit tests: mock `OllamaClient` in `InMemorySessionServiceTest` to verify two-call pattern and state merge; optionally integration test with a real or stubbed Ollama.
---
## Risks and mitigations
| Risk | Mitigation |
|------|------------|
| Ollama slow/unavailable | Timeouts already set in rest-client config; fail fast and return 502/503 from resource layer. |
| Model returns invalid JSON (Call 2) | Already throws `OllamaParseException`; map to 502 or 503 in a mapper if not already. |
| Large context / token limit | Keep recentHistorySummary short; later add condensing of older turns. |
| Enum mismatches (API vs common) | Use same enum names in OpenAPI as in common (e.g. speech, action, reaction); document mapping in one place. |
---
## Files to touch (summary)
| File / area | Change |
|------------|--------|
| New: e.g. `business/OllamaPrompts.java` | System prompt constants for init narrative, turn narrative, state extraction. |
| New or existing: mappers / context builder | Build `TurnContext` from scenario or session + turnRequest; map StateUpdateResponse → SessionResponse / TurnResponse. |
| [InMemorySessionService](src/main/java/de/neitzel/roleplay/business/InMemorySessionService.java) | Inject `OllamaClient`, `ObjectMapper`; implement createSession and submitTurn with two-call pattern and state merge; remove TODOs and placeholder narratives. |
| [InMemorySessionServiceTest](src/test/java/de/neitzel/roleplay/business/InMemorySessionServiceTest.java) | Add or adjust tests with mocked OllamaClient to verify createSession and submitTurn call Ollama and merge state. |
| Optional: exception mapper | Map `OllamaParseException` (and network errors) to a suitable HTTP response if not already. |
---
## Done criteria
- **createSession**: Opening narrative and initial situation/characters/suggestions come from Ollama (Call 1 + Call 2); no placeholder text.
- **submitTurn**: Turn narrative and updated situation/characters/suggestions come from Ollama; session state is updated; TurnResponse contains narrative and structured state (characterResponses, updatedSituation, updatedCharacters, suggestions).
- Unit tests cover the two-call flow with mocked OllamaClient and assert on state merge.
- No remaining TODOs in InMemorySessionService for Ollama integration.