Disable the battalion backstory popup that appears on hover in the Heroes & Battalions panel. This is the first stage of eliminating battalion backstory LLM updates to reduce request volume. The popup panel is now always hidden when hovering over battalions. Hero backstories are unaffected. See docs/eliminate-battalion-backstory-updates.md for the full plan. Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
7.5 KiB
Plan: Eliminate Battalion Backstory LLM Updates
Goal
Dramatically reduce LLM request volume by eliminating battalion backstory updates. Battalions will retain:
- An initial backstory (generated once when created)
- A history of events (structured data, not LLM-generated prose)
The history will be fed into other LLM updates (hero backstories, chronicle) but will no longer be regenerated into prose for each battalion.
Current System Overview
Data Flow
Battalion Created → Initial Backstory LLM Request → Text stored
↓
Battalion participates in events → Events accumulated → Update LLM Request → New text version
↓
BattalionView.backstoryTextId → Client displays on hover
Event Types (8 total)
Events are structured data already captured in EventForBattalionBackstory:
- OrganizedTroops, SuppressedBeasts, ApprehendedOutlaws, FoughtInBattle
- SuppressedRiot, Trained, Armed, SurvivedStarvation
Each event has date, province, hero, and event-specific details.
Key Files
| Component | File |
|---|---|
| Unity Display | Assets/Eagle/HeroesAndBattalionsPanelController.cs |
| View Proto | views/battalion_view.proto |
| View Filter | BattalionViewFilter.scala |
| Update Action | BattalionBackstoryUpdateAction.scala |
| Update Generator | BattalionBackstoryUpdateActionGenerator.scala |
| Update Prompt | BattalionBackstoryUpdatePromptGenerator.scala |
| Event-to-Text | BattalionBackstoryUpdatePromptGenerator.textForEvent() |
| BattalionDescriptions | BattalionDescriptions.scala (used in other LLM prompts) |
Stage 1: Stop Displaying Battalion Backstories in Client
Goal: Remove the UI that shows battalion backstory text on hover.
Files to Modify
Assets/Eagle/HeroesAndBattalionsPanelController.cs
- In
BattalionLongHoverRowChanged()(lines 143-169):- Remove or comment out the backstory text population
- Keep the header/name display, remove
battalionPopupPanelBackstory.TextId = ...
Unity Scene/Prefab
- Hide or remove the
battalionPopupPanelBackstoryUI element
Verification
- Battalion hover popup no longer shows backstory text
- No errors when hovering over battalions
- Other battalion info (name, type, size) still displays
Stage 2: Stop Populating Backstory in BattalionView
Goal: Stop sending backstory text ID to the client.
Files to Modify
BattalionViewFilter.scala
- In
filteredBattalionViewBelongingToPlayer():- Set
backstoryTextId = ""instead ofbattalion.backstoryTextId
- Set
- In
limitedBattalionView():- Same change
Verification
- BattalionView messages have empty backstoryTextId
- Client handles empty backstoryTextId gracefully (Stage 1 should have removed the display)
Stage 3: Remove backstory_text_id from BattalionView Proto
Goal: Clean up the proto schema.
Files to Modify
views/battalion_view.proto
- Remove field:
string backstory_text_id = 7; - Mark field 7 as reserved to prevent reuse
Assets/Eagle/HeroesAndBattalionsPanelController.cs
- Remove any remaining references to
BackstoryTextId
BattalionViewFilter.scala
- Remove
backstoryTextIdfrom view construction
Verification
- Proto compiles
- C# client compiles without BackstoryTextId references
- Full test suite passes
Stage 4: Replace Backstory Usage in BattalionDescriptions
Goal: When other LLM prompts need battalion context, use initial backstory + structured history instead of the latest LLM-generated prose.
Current Usage in BattalionDescriptions.scala
def backstoryText(): TextGenerationResult =
battalion.backstoryVersions.lastOption
.map(v => clientTextStore.getText(v.textId))
.getOrElse(TextGenerationSuccess(""))
def fullDescription(): String =
s"${battalion.name} is $description. $backstoryText"
New Approach
Create historyDescription() that:
- Gets initial backstory (first version's text, if available)
- Appends structured event history using the same
textForEvent()logic fromBattalionBackstoryUpdatePromptGenerator
def historyDescription(): String = {
val initialBackstory = battalion.backstoryVersions.headOption
.map(v => clientTextStore.getText(v.textId))
.collect { case TextGenerationSuccess(text) => text }
.getOrElse("")
val eventHistory = battalion.backstoryEvents
.map(textForEvent) // Reuse existing event-to-text conversion
.mkString(" ")
if eventHistory.isEmpty then initialBackstory
else s"$initialBackstory $eventHistory"
}
Files to Modify
BattalionDescriptions.scala
- Add
historyDescription()method - Update
fullDescription()to usehistoryDescription()instead ofbackstoryText() - Keep
textForEvent()logic (move fromBattalionBackstoryUpdatePromptGeneratorif needed)
Move/refactor textForEvent()
- Currently in
BattalionBackstoryUpdatePromptGenerator.scala(lines 78-262) - Move to
BattalionDescriptions.scalaor a shared utility - This converts events to human-readable text without LLM
Verification
- Other LLM prompts that use
BattalionDescriptionsstill get meaningful context - Chronicle updates include battalion history
- Hero backstory updates include relevant battalion history
Stage 5: Stop Generating Battalion Backstory Updates
Goal: Remove the LLM request generation entirely.
Files to Modify
BattalionBackstoryUpdateActionGenerator.scala
- Return empty Vector instead of generating actions
- Or delete the file entirely
BattalionBackstoryUpdateAction.scala
- Delete or mark as deprecated
BattalionBackstoryUpdatePromptGenerator.scala
- Delete or keep only
textForEvent()if moved
LlmResolver.scala
- Remove case for
BattalionBackstoryUpdateRequest - Optionally throw error if somehow called
EndPlayerCommandsPhaseAction.scala (and other callers)
- Find where
BattalionBackstoryUpdateActionGeneratoris called - Remove those calls
Files to Search for Callers
grep -r "BattalionBackstoryUpdateAction" src/
Verification
- No
BattalionBackstoryUpdateRequestLLM requests generated - Battalions still accumulate events (for history description)
- Full test suite passes
- Game runs without errors
Future Considerations
Keep or Remove Initial Backstory Generation?
The initial backstory (BattalionInitialBackstoryRequest) is generated once per battalion. Options:
- Keep it - Low volume, provides flavor text for history
- Remove it - Use a template-based approach instead
Recommendation: Keep for now, evaluate later based on volume.
Event History Cleanup
Events currently accumulate forever on battalions. Consider:
- Capping event history length
- Summarizing old events
- Only keeping "significant" events
Affected Tests
Search for tests that verify backstory update behavior:
bazel query 'tests(//src/test/scala/...) intersect rdeps(//src/test/scala/..., //src/main/scala/net/eagle0/eagle/library/actions/impl/action:battalion_backstory_update_action)'
Summary of LLM Request Reduction
| Request Type | Current Volume | After Change |
|---|---|---|
| BattalionInitialBackstoryRequest | 1 per battalion | 1 per battalion (unchanged) |
| BattalionBackstoryUpdateRequest | ~N per battalion per game | 0 |
For a typical game with ~50 battalions and ~20 rounds, this could eliminate hundreds of LLM requests.