@@ -2,9 +2,14 @@ package link.socket.ampere.agents.domain.cognition.sparks
22
33import kotlinx.coroutines.NonCancellable
44import kotlinx.coroutines.withContext
5+ import kotlinx.datetime.Clock
56import link.socket.ampere.agents.config.PhaseSparkConfig
67import link.socket.ampere.agents.definition.AutonomousAgent
8+ import link.socket.ampere.agents.domain.event.CognitivePhaseEvent
9+ import link.socket.ampere.agents.domain.event.EventSource
710import link.socket.ampere.agents.domain.state.AgentState
11+ import link.socket.ampere.agents.events.bus.EventSerialBus
12+ import link.socket.ampere.agents.events.utils.generateUUID
813import link.socket.ampere.util.getEnvironmentVariable
914
1015/* *
@@ -24,20 +29,25 @@ class PhaseSparkManager<S : AgentState> private constructor(
2429 val enabled : Boolean ,
2530 private val activePhases : Set <CognitivePhase >,
2631 private val library : PhaseSparkLibrary ? ,
32+ private val eventBus : EventSerialBus ? ,
2733) {
2834 constructor (
2935 agent: AutonomousAgent <S >,
3036 enabled: Boolean = isPhaseSparkEnabled(),
3137 activePhases: Set <CognitivePhase > = DEFAULT_PHASES ,
38+ eventBus: EventSerialBus ? = null ,
3239 ) : this (
3340 agent = agent,
3441 enabled = enabled,
3542 activePhases = activePhases,
3643 library = null ,
44+ eventBus = eventBus,
3745 )
3846
3947 private var appliedSparks: MutableList <PhaseSpark > = mutableListOf ()
4048 private var currentPhase: CognitivePhase ? = null
49+ private var currentPhaseNestingDepth: Int = 0
50+ private var withPhaseNestingDepth: Int = 0
4151
4252 fun enterPhase (phase : CognitivePhase ) {
4353 enterPhaseInternal(phase, selectionContext = null )
@@ -47,9 +57,15 @@ class PhaseSparkManager<S : AgentState> private constructor(
4757 enterPhaseInternal(phase, selectionContext)
4858 }
4959
50- private fun enterPhaseInternal (phase : CognitivePhase , selectionContext : SparkSelectionContext ? ) {
60+ private fun enterPhaseInternal (
61+ phase : CognitivePhase ,
62+ selectionContext : SparkSelectionContext ? ,
63+ nestingDepth : Int = 0,
64+ oldPhaseOverride : CognitivePhase ? = null,
65+ ) {
5166 if (! enabled) return
5267
68+ val oldPhase = oldPhaseOverride ? : currentPhase
5369 if (appliedSparks.isNotEmpty() && currentPhase != phase) {
5470 removeAppliedSparks()
5571 }
@@ -67,11 +83,13 @@ class PhaseSparkManager<S : AgentState> private constructor(
6783 }
6884
6985 agent.currentCognitivePhase = phase
86+ publishPhaseEntered(oldPhase = oldPhase, newPhase = phase, nestingDepth = nestingDepth)
7087 for (spark in sparksToApply) {
7188 agent.spark<AutonomousAgent <S >>(spark)
7289 appliedSparks + = spark
7390 }
7491 currentPhase = phase
92+ currentPhaseNestingDepth = nestingDepth
7593 }
7694
7795 suspend fun <R > withPhase (phase : CognitivePhase , block : suspend () -> R ): R =
@@ -89,26 +107,41 @@ class PhaseSparkManager<S : AgentState> private constructor(
89107 block : suspend () -> R ,
90108 ): R {
91109 if (! enabled) return block()
110+ if (! isPhaseEnabled(phase)) return block()
92111
112+ val nestingDepth = withPhaseNestingDepth
93113 val previousPhase = currentPhase
94114 val previousSparks = appliedSparks.toList()
115+ val previousPhaseNestingDepth = currentPhaseNestingDepth
95116 appliedSparks = mutableListOf ()
96117 currentPhase = null
97- enterPhaseInternal(phase, selectionContext)
118+ enterPhaseInternal(
119+ phase = phase,
120+ selectionContext = selectionContext,
121+ nestingDepth = nestingDepth,
122+ oldPhaseOverride = previousPhase,
123+ )
124+ withPhaseNestingDepth = nestingDepth + 1
98125
99126 return try {
100127 block()
101128 } finally {
102129 withContext(NonCancellable ) {
103- removeAppliedSparks()
130+ withPhaseNestingDepth = nestingDepth
131+ removeAppliedSparks(
132+ restoredToPhase = previousPhase,
133+ nestingDepth = nestingDepth,
134+ )
104135
105136 if (previousPhase != null && previousSparks.isNotEmpty()) {
106- agent.currentCognitivePhase = previousPhase
107- for (spark in previousSparks) {
108- agent.spark<AutonomousAgent <S >>(spark)
109- appliedSparks + = spark
110- }
137+ appliedSparks = previousSparks.toMutableList()
111138 currentPhase = previousPhase
139+ currentPhaseNestingDepth = previousPhaseNestingDepth
140+ publishPhaseEntered(
141+ oldPhase = phase,
142+ newPhase = previousPhase,
143+ nestingDepth = previousPhaseNestingDepth,
144+ )
112145 }
113146 }
114147 }
@@ -126,14 +159,64 @@ class PhaseSparkManager<S : AgentState> private constructor(
126159
127160 private fun isPhaseEnabled (phase : CognitivePhase ): Boolean = activePhases.contains(phase)
128161
129- private fun removeAppliedSparks () {
162+ private fun removeAppliedSparks (
163+ restoredToPhase : CognitivePhase ? = null,
164+ nestingDepth : Int = currentPhaseNestingDepth,
165+ ) {
130166 if (appliedSparks.isEmpty()) return
167+ val exitedPhase = currentPhase ? : return
131168 repeat(appliedSparks.size) {
132169 agent.unspark()
133170 }
134171 appliedSparks.clear()
135172 currentPhase = null
136- agent.currentCognitivePhase = null
173+ currentPhaseNestingDepth = 0
174+ agent.currentCognitivePhase = restoredToPhase
175+ publishPhaseExited(
176+ exitedPhase = exitedPhase,
177+ restoredToPhase = restoredToPhase,
178+ nestingDepth = nestingDepth,
179+ )
180+ }
181+
182+ private fun publishPhaseEntered (
183+ oldPhase : CognitivePhase ? ,
184+ newPhase : CognitivePhase ,
185+ nestingDepth : Int ,
186+ ) {
187+ eventBus?.let { bus ->
188+ bus.publishAsync(
189+ CognitivePhaseEvent .PhaseEntered (
190+ eventId = generateUUID(agent.id, newPhase.name, nestingDepth.toString()),
191+ timestamp = Clock .System .now(),
192+ eventSource = EventSource .Agent (agent.id),
193+ agentId = agent.id,
194+ oldPhase = oldPhase,
195+ newPhase = newPhase,
196+ nestingDepth = nestingDepth,
197+ ),
198+ )
199+ }
200+ }
201+
202+ private fun publishPhaseExited (
203+ exitedPhase : CognitivePhase ,
204+ restoredToPhase : CognitivePhase ? ,
205+ nestingDepth : Int ,
206+ ) {
207+ eventBus?.let { bus ->
208+ bus.publishAsync(
209+ CognitivePhaseEvent .PhaseExited (
210+ eventId = generateUUID(agent.id, exitedPhase.name, nestingDepth.toString()),
211+ timestamp = Clock .System .now(),
212+ eventSource = EventSource .Agent (agent.id),
213+ agentId = agent.id,
214+ exitedPhase = exitedPhase,
215+ restoredToPhase = restoredToPhase,
216+ nestingDepth = nestingDepth,
217+ ),
218+ )
219+ }
137220 }
138221
139222 companion object {
@@ -159,30 +242,35 @@ class PhaseSparkManager<S : AgentState> private constructor(
159242 fun <S : AgentState > create (
160243 agent : AutonomousAgent <S >,
161244 phaseConfig : PhaseSparkConfig ? = null,
162- ): PhaseSparkManager <S > = createInternal(agent, phaseConfig, library = null )
245+ eventBus : EventSerialBus ? = null,
246+ ): PhaseSparkManager <S > = createInternal(agent, phaseConfig, library = null , eventBus = eventBus)
163247
164248 internal fun <S : AgentState > createWithLibrary (
165249 agent : AutonomousAgent <S >,
166250 phaseConfig : PhaseSparkConfig ? = null,
167251 library : PhaseSparkLibrary ? = null,
168- ): PhaseSparkManager <S > = createInternal(agent, phaseConfig, library)
252+ eventBus : EventSerialBus ? = null,
253+ ): PhaseSparkManager <S > = createInternal(agent, phaseConfig, library, eventBus)
169254
170255 internal fun <S : AgentState > internalCreate (
171256 agent : AutonomousAgent <S >,
172257 enabled : Boolean ,
173258 activePhases : Set <CognitivePhase > = DEFAULT_PHASES ,
174259 library : PhaseSparkLibrary ? = null,
260+ eventBus : EventSerialBus ? = null,
175261 ): PhaseSparkManager <S > = PhaseSparkManager (
176262 agent = agent,
177263 enabled = enabled,
178264 activePhases = activePhases,
179265 library = library,
266+ eventBus = eventBus,
180267 )
181268
182269 private fun <S : AgentState > createInternal (
183270 agent : AutonomousAgent <S >,
184271 phaseConfig : PhaseSparkConfig ? ,
185272 library : PhaseSparkLibrary ? ,
273+ eventBus : EventSerialBus ? ,
186274 ): PhaseSparkManager <S > {
187275 val enabledFromConfig = phaseConfig?.enabled ? : false
188276 val enabled = enabledFromConfig || isPhaseSparkEnabled()
@@ -192,6 +280,7 @@ class PhaseSparkManager<S : AgentState> private constructor(
192280 enabled = enabled,
193281 activePhases = phases,
194282 library = library,
283+ eventBus = eventBus,
195284 )
196285 }
197286 }
0 commit comments