feat(personalization): OperatorProfileBoundEvent + bind-at-start + inject about context

Records operator profile as a snapshot event at session start (invariants #8/#9),
populates SessionState.boundProfile via reducer, and injects the about text as a
pinned L0 SYSTEM context entry in every stage. Gated by PersonalizationConfig.enabled.
This commit is contained in:
2026-06-08 10:38:47 +04:00
parent 76b19e2f63
commit 0c7fa70f8d
10 changed files with 221 additions and 1 deletions
@@ -333,8 +333,23 @@ abstract class SessionOrchestrator(
)
val repoMapEntries = buildRepoMapEntries(sessionId)
val needsEntries = buildNeedsArtifactEntries(sessionId, stageConfig)
val profileEntries = session.state.boundProfile?.about
?.takeIf { it.isNotBlank() }
?.let { about ->
listOf(
ContextEntry(
id = ContextEntryId(UUID.randomUUID().toString()),
layer = ContextLayer.L0,
content = "## Operator profile\n$about",
sourceType = "operatorProfile",
sourceId = "operator-profile",
tokenEstimate = about.length / 4,
role = EntryRole.SYSTEM,
),
)
} ?: emptyList()
var accumulatedEntries =
systemPrompt + journalEntries + repoMapEntries + needsEntries +
systemPrompt + profileEntries + journalEntries + repoMapEntries + needsEntries +
schemaEntries + promptEntries + steeringEntries
val contextPack = contextPackBuilder.build(
id = ContextPackId(UUID.randomUUID().toString()),