Show per-turn stat changes under each AI message

Each AI action now carries a compact world_changes summary (derived from its
stored snapshot), rendered as small chips beneath the message: numeric stats
show a signed delta (green up / red down), flags show on/off, milestones show
a check. Gives an at-a-glance "what changed" without opening Insights.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parththakkar106
2026-07-21 16:48:35 +05:30
co-authored by Claude Opus 4.8
parent 3b03bf737a
commit 279110f75b
5 changed files with 86 additions and 0 deletions
+22
View File
@@ -799,6 +799,28 @@ button:disabled { opacity: 0.45; cursor: default; transform: none; box-shadow: n
.se-band-l { flex: 1; padding: 3px 6px; font-size: 0.82rem; }
.ws-report { list-style: none; margin: 4px 0 0; padding: 0; font-size: 0.82rem; }
.ws-report li { padding: 2px 0; color: var(--text); }
/* Inline per-turn change chips under an AI message */
.turn-changes {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-top: 8px;
}
.chg {
font-size: 0.74rem;
padding: 2px 8px;
border-radius: 10px;
border: 1px solid var(--border);
background: var(--bg-input);
color: var(--text-dim);
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.chg-up { color: var(--player, #4caf82); border-color: color-mix(in srgb, var(--player, #4caf82) 40%, var(--border)); }
.chg-down { color: var(--danger, #e5484d); border-color: color-mix(in srgb, var(--danger, #e5484d) 40%, var(--border)); }
.chg-flag { color: var(--accent-bright); }
.chg-ms { color: var(--accent-bright); border-color: color-mix(in srgb, var(--accent-bright) 40%, var(--border)); }
.ws-report code { color: var(--accent-bright); }
.ws-delta { color: var(--player); font-variant-numeric: tabular-nums; }
.ws-flag { color: var(--text-dim); font-style: italic; }
+23
View File
@@ -622,6 +622,28 @@ function WorldStateDrawer({ advId, refreshKey }) {
)
}
// Compact chips shown under an AI message summarizing what state changed.
function StateChangeChips({ changes }) {
if (!changes?.length) return null
const nice = (s) => String(s).replace(/_/g, ' ')
return (
<div className="turn-changes">
{changes.map((c, i) => {
if (c.kind === 'flag') {
return <span key={i} className="chg chg-flag">{nice(c.label)}: {c.on ? 'on' : 'off'}</span>
}
if (c.kind === 'milestone') {
return <span key={i} className="chg chg-ms">✓ {nice(c.label)}</span>
}
const d = c.delta
const dir = typeof d === 'number' ? (d > 0 ? 'up' : d < 0 ? 'down' : 'flat') : 'flat'
const txt = typeof d === 'number' ? (d > 0 ? `+${d}` : `${d}`) : `→ ${c.value}`
return <span key={i} className={`chg chg-stat chg-${dir}`}>{nice(c.label)} {txt}</span>
})}
</div>
)
}
// Per-turn RPG state change, shown when inspecting a past turn's snapshot.
function WorldStateReport({ worldState }) {
if (!worldState) return null
@@ -1021,6 +1043,7 @@ export default function Play() {
className={`action ${PLAYER_TYPES.includes(action.type) ? 'player' : ''}`}>
<ReasoningBlock text={action.reasoning} />
{renderEmphasis(action.text)}
{action.type === 'ai' && <StateChangeChips changes={action.world_changes} />}
{!busy && (
<span className="action-tools">
{action.type === 'ai' && (