RolePlay/docs/OPEN_TASKS_PLAN.md
Konrad Neitzel b79334ee67 Implement Ollama integration for session management and turn processing
- Enhance InMemorySessionService to utilize the two-call Ollama pattern for session creation and turn submissions, generating narratives and state updates based on provided scenarios.
- Introduce OllamaContextBuilder to construct turn contexts for both session initialization and turn continuation.
- Add OllamaPrompts class to define system prompts for narrative generation and state extraction.
- Implement StateUpdateMapper to handle merging state updates into session responses.
- Create unit tests for InMemorySessionService to validate Ollama interactions and ensure correct session state management.
2026-02-21 12:45:20 +01:00

12 KiB
Raw Blame History

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.


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 already provides generateNarrative(model, systemPrompt, userContent) and generateStateUpdate(model, systemPrompt, userContent).
  • Common types (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 (§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 Inject OllamaClient, ObjectMapper; implement createSession and submitTurn with two-call pattern and state merge; remove TODOs and placeholder narratives.
InMemorySessionServiceTest 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.