Skip to content

Commit c1f1e70

Browse files
committed
Introduce PlannerFactory
1 parent 8843757 commit c1f1e70

File tree

11 files changed

+117
-14
lines changed

11 files changed

+117
-14
lines changed

embabel-agent-api/src/main/kotlin/com/embabel/agent/core/support/ConcurrentAgentProcess.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package com.embabel.agent.core.support
1818

1919
import com.embabel.agent.api.common.PlatformServices
2020
import com.embabel.agent.core.*
21+
import com.embabel.agent.spi.PlannerFactory
2122
import com.embabel.plan.WorldState
2223
import com.embabel.plan.goap.GoapWorldState
2324
import kotlinx.coroutines.future.await
@@ -37,6 +38,7 @@ open class ConcurrentAgentProcess(
3738
processOptions: ProcessOptions,
3839
blackboard: Blackboard,
3940
platformServices: PlatformServices,
41+
plannerFactory: PlannerFactory,
4042
timestamp: Instant = Instant.now(),
4143
val callbacks: List<AgentProcessCallback> = emptyList(),
4244
) : SimpleAgentProcess(
@@ -46,6 +48,7 @@ open class ConcurrentAgentProcess(
4648
processOptions = processOptions,
4749
blackboard = blackboard,
4850
platformServices = platformServices,
51+
plannerFactory = plannerFactory,
4952
timestamp = timestamp,
5053
) {
5154
override fun formulateAndExecutePlan(worldState: WorldState): AgentProcess {

embabel-agent-api/src/main/kotlin/com/embabel/agent/core/support/DefaultAgentPlatform.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,18 @@ package com.embabel.agent.core.support
1717

1818
import com.embabel.agent.api.common.Asyncer
1919
import com.embabel.agent.channel.OutputChannel
20-
import com.embabel.agent.spi.config.spring.AgentPlatformProperties
2120
import com.embabel.agent.core.*
2221
import com.embabel.agent.event.AgentDeploymentEvent
2322
import com.embabel.agent.event.AgentProcessCreationEvent
2423
import com.embabel.agent.event.AgenticEventListener
2524
import com.embabel.agent.spi.*
25+
import com.embabel.agent.spi.config.spring.AgentPlatformProperties
26+
import com.embabel.agent.spi.support.GoapPlannerFactory
2627
import com.embabel.agent.spi.support.InMemoryAgentProcessRepository
2728
import com.embabel.agent.spi.support.InMemoryContextRepository
2829
import com.embabel.agent.spi.support.SpringContextPlatformServices
2930
import com.embabel.common.textio.template.TemplateRenderer
3031
import com.fasterxml.jackson.databind.ObjectMapper
31-
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory
32-
import com.fasterxml.jackson.module.kotlin.registerKotlinModule
3332
import org.slf4j.LoggerFactory
3433
import org.springframework.beans.factory.annotation.Autowired
3534
import org.springframework.beans.factory.annotation.Value
@@ -64,7 +63,7 @@ open class DefaultAgentPlatform(
6463

6564
private val logger = LoggerFactory.getLogger(DefaultAgentPlatform::class.java)
6665

67-
private val yamlObjectMapper = ObjectMapper(YAMLFactory()).registerKotlinModule()
66+
private val plannerFactory: PlannerFactory = GoapPlannerFactory
6867

6968
private val agents: MutableMap<String, Agent> = ConcurrentHashMap()
7069

@@ -176,6 +175,7 @@ open class DefaultAgentPlatform(
176175
id = id,
177176
parentId = null,
178177
processOptions = processOptions,
178+
plannerFactory = plannerFactory,
179179
)
180180

181181
AgentPlatformProperties.ProcessType.CONCURRENT -> ConcurrentAgentProcess(
@@ -185,6 +185,7 @@ open class DefaultAgentPlatform(
185185
id = id,
186186
parentId = null,
187187
processOptions = processOptions,
188+
plannerFactory = plannerFactory,
188189
callbacks = callbacks,
189190
)
190191
}
@@ -212,6 +213,7 @@ open class DefaultAgentPlatform(
212213
}",
213214
parentId = parentAgentProcess.id,
214215
processOptions = processOptions,
216+
plannerFactory = plannerFactory,
215217
)
216218
logger.debug("👶 Creating child process {} from {}", childAgentProcess.id, parentAgentProcess.id)
217219
agentProcessRepository.save(childAgentProcess)

embabel-agent-api/src/main/kotlin/com/embabel/agent/core/support/SimpleAgentProcess.kt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ import com.embabel.agent.api.common.PlatformServices
1919
import com.embabel.agent.core.*
2020
import com.embabel.agent.event.AgentProcessPlanFormulatedEvent
2121
import com.embabel.agent.event.GoalAchievedEvent
22+
import com.embabel.agent.spi.PlannerFactory
2223
import com.embabel.common.util.indentLines
2324
import com.embabel.plan.Plan
2425
import com.embabel.plan.Planner
2526
import com.embabel.plan.WorldState
26-
import com.embabel.plan.goap.AStarGoapPlanner
2727
import com.embabel.plan.goap.WorldStateDeterminer
2828
import java.time.Instant
2929

@@ -34,6 +34,7 @@ open class SimpleAgentProcess(
3434
processOptions: ProcessOptions,
3535
blackboard: Blackboard,
3636
platformServices: PlatformServices,
37+
plannerFactory: PlannerFactory,
3738
timestamp: Instant = Instant.now(),
3839
) : AbstractAgentProcess(
3940
id = id,
@@ -52,7 +53,7 @@ open class SimpleAgentProcess(
5253

5354
override val worldStateDeterminer: WorldStateDeterminer = BlackboardWorldStateDeterminer(processContext)
5455

55-
override val planner: Planner<*, *, *> = AStarGoapPlanner(worldStateDeterminer)
56+
override val planner: Planner<*, *, *> = plannerFactory.createPlanner(processOptions, worldStateDeterminer)
5657

5758
override fun recordLlmInvocation(llmInvocation: LlmInvocation) {
5859
_llmInvocations.add(llmInvocation)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2024-2025 Embabel Software, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.embabel.agent.spi
17+
18+
import com.embabel.agent.core.ProcessOptions
19+
import com.embabel.plan.Plan
20+
import com.embabel.plan.Planner
21+
import com.embabel.plan.PlanningSystem
22+
import com.embabel.plan.WorldState
23+
import com.embabel.plan.goap.WorldStateDeterminer
24+
25+
/**
26+
* Pluggable planner factory
27+
*/
28+
fun interface PlannerFactory {
29+
30+
fun createPlanner(
31+
processOptions: ProcessOptions,
32+
worldStateDeterminer: WorldStateDeterminer,
33+
): Planner<out PlanningSystem, out WorldState, out Plan>
34+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2024-2025 Embabel Software, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.embabel.agent.spi.support
17+
18+
import com.embabel.agent.core.ProcessOptions
19+
import com.embabel.agent.spi.PlannerFactory
20+
import com.embabel.plan.Plan
21+
import com.embabel.plan.Planner
22+
import com.embabel.plan.PlanningSystem
23+
import com.embabel.plan.WorldState
24+
import com.embabel.plan.goap.AStarGoapPlanner
25+
import com.embabel.plan.goap.WorldStateDeterminer
26+
27+
/**
28+
* PlannerFactory that always creates AStarGoapPlanner
29+
*/
30+
object GoapPlannerFactory : PlannerFactory {
31+
override fun createPlanner(
32+
processOptions: ProcessOptions,
33+
worldStateDeterminer: WorldStateDeterminer,
34+
): Planner<out PlanningSystem, out WorldState, out Plan> {
35+
return AStarGoapPlanner(worldStateDeterminer)
36+
}
37+
}

embabel-agent-api/src/main/kotlin/com/embabel/agent/testing/integration/IntegrationTestUtils.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ package com.embabel.agent.testing.integration
1717

1818
import com.embabel.agent.api.common.PlatformServices
1919
import com.embabel.agent.channel.DevNullOutputChannel
20-
import com.embabel.agent.spi.config.spring.AgentPlatformProperties.ProcessType
2120
import com.embabel.agent.core.*
2221
import com.embabel.agent.core.support.DefaultAgentPlatform
2322
import com.embabel.agent.core.support.InMemoryBlackboard
@@ -26,7 +25,9 @@ import com.embabel.agent.event.AgenticEventListener
2625
import com.embabel.agent.spi.LlmOperations
2726
import com.embabel.agent.spi.OperationScheduler
2827
import com.embabel.agent.spi.ToolGroupResolver
28+
import com.embabel.agent.spi.config.spring.AgentPlatformProperties.ProcessType
2929
import com.embabel.agent.spi.support.ExecutorAsyncer
30+
import com.embabel.agent.spi.support.GoapPlannerFactory
3031
import com.embabel.agent.spi.support.RegistryToolGroupResolver
3132
import com.embabel.agent.spi.support.SpringContextPlatformServices
3233
import com.embabel.agent.testing.common.EventSavingAgenticEventListener
@@ -93,6 +94,7 @@ object IntegrationTestUtils {
9394
blackboard = InMemoryBlackboard(),
9495
processOptions = ProcessOptions(),
9596
platformServices = platformServices ?: dummyPlatformServices(),
97+
plannerFactory = GoapPlannerFactory,
9698
)
9799
}
98100

embabel-agent-api/src/test/java/com/embabel/agent/api/annotation/support/PackageVisibleTests.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import com.embabel.agent.core.ProcessOptions;
2929
import com.embabel.agent.core.support.InMemoryBlackboard;
3030
import com.embabel.agent.core.support.SimpleAgentProcess;
31+
import com.embabel.agent.spi.support.GoapPlannerFactory;
3132
import org.junit.jupiter.api.Test;
3233

3334
import java.time.Instant;
@@ -77,6 +78,7 @@ public void actionInvocationWithJavaPackageVisibleParameters() {
7778
processOptions,
7879
new InMemoryBlackboard(),
7980
platformServices,
81+
GoapPlannerFactory.INSTANCE,
8082
Instant.now()
8183
)
8284
);
@@ -109,6 +111,7 @@ public void conditionInvocationWithJavaPackageVisibleConditionMethod() {
109111
processOptions,
110112
new InMemoryBlackboard(),
111113
platformServices,
114+
GoapPlannerFactory.INSTANCE,
112115
Instant.now()
113116
)
114117
);

embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReaderActionTest.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import com.embabel.agent.domain.io.UserInput
2727
import com.embabel.agent.event.AgenticEventListener.Companion.DevNull
2828
import com.embabel.agent.spi.LlmInteraction
2929
import com.embabel.agent.spi.LlmOperations
30+
import com.embabel.agent.spi.support.GoapPlannerFactory
3031
import com.embabel.agent.support.Dog
3132
import com.embabel.agent.testing.integration.IntegrationTestUtils
3233
import com.embabel.agent.testing.integration.IntegrationTestUtils.dummyAgentProcessRunning
@@ -312,6 +313,7 @@ class AgentMetadataReaderActionTest {
312313
platformServices = platformServices,
313314
processOptions = ProcessOptions(),
314315
blackboard = InMemoryBlackboard(),
316+
plannerFactory = GoapPlannerFactory,
315317
parentId = null,
316318
),
317319
platformServices = platformServices,
@@ -436,6 +438,7 @@ class AgentMetadataReaderActionTest {
436438
platformServices = platformServices,
437439
processOptions = ProcessOptions(),
438440
blackboard = InMemoryBlackboard(),
441+
plannerFactory = GoapPlannerFactory,
439442
parentId = null,
440443
),
441444
platformServices = platformServices,

embabel-agent-api/src/test/kotlin/com/embabel/agent/api/dsl/AgentBuilderTest.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import com.embabel.agent.core.ProcessContext
2222
import com.embabel.agent.core.ProcessOptions
2323
import com.embabel.agent.core.support.InMemoryBlackboard
2424
import com.embabel.agent.core.support.SimpleAgentProcess
25+
import com.embabel.agent.spi.support.GoapPlannerFactory
2526
import com.embabel.agent.support.Dog
2627
import com.embabel.agent.testing.integration.IntegrationTestUtils.dummyPlatformServices
2728
import com.embabel.common.core.types.Semver
@@ -109,6 +110,7 @@ class AgentBuilderTest {
109110
processOptions = ProcessOptions(blackboard = blackboard),
110111
platformServices = platformServices,
111112
id = "test",
113+
plannerFactory = GoapPlannerFactory,
112114
parentId = null,
113115
),
114116
processOptions = ProcessOptions(blackboard = blackboard),
@@ -138,6 +140,7 @@ class AgentBuilderTest {
138140
processOptions = ProcessOptions(blackboard = blackboard),
139141
platformServices = platformServices,
140142
id = "test",
143+
plannerFactory = GoapPlannerFactory,
141144
parentId = null,
142145
),
143146
processOptions = ProcessOptions(blackboard = blackboard),

embabel-agent-api/src/test/kotlin/com/embabel/agent/core/support/ConcurrentAgentProcessTest.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,18 @@
1515
*/
1616
package com.embabel.agent.core.support
1717

18-
import com.embabel.agent.api.annotation.AchievesGoal
19-
import com.embabel.agent.api.annotation.Action
20-
import com.embabel.agent.api.annotation.confirm
2118
import com.embabel.agent.api.annotation.support.AgentMetadataReader
22-
import com.embabel.agent.api.annotation.waitFor
2319
import com.embabel.agent.api.common.StuckHandler
2420
import com.embabel.agent.api.common.StuckHandlerResult
2521
import com.embabel.agent.api.common.StuckHandlingResultCode
2622
import com.embabel.agent.api.dsl.Frog
27-
import com.embabel.agent.api.dsl.agent
2823
import com.embabel.agent.api.dsl.evenMoreEvilWizard
2924
import com.embabel.agent.core.*
3025
import com.embabel.agent.core.hitl.ConfirmationRequest
3126
import com.embabel.agent.domain.io.UserInput
32-
import com.embabel.agent.domain.library.Person
3327
import com.embabel.agent.event.ObjectAddedEvent
3428
import com.embabel.agent.event.ObjectBoundEvent
35-
import com.embabel.agent.support.Dog
29+
import com.embabel.agent.spi.support.GoapPlannerFactory
3630
import com.embabel.agent.support.SimpleTestAgent
3731
import com.embabel.agent.testing.common.EventSavingAgenticEventListener
3832
import com.embabel.agent.testing.integration.IntegrationTestUtils.dummyPlatformServices
@@ -58,6 +52,7 @@ class ConcurrentAgentProcessTest {
5852
blackboard = InMemoryBlackboard(),
5953
platformServices = dummyPlatformServices(),
6054
parentId = null,
55+
plannerFactory = GoapPlannerFactory,
6156
)
6257
assertThrows<IOException> {
6358
jacksonObjectMapper().writeValueAsString(cap)
@@ -99,6 +94,7 @@ class ConcurrentAgentProcessTest {
9994
blackboard = blackboard,
10095
platformServices = dummyPlatformServices,
10196
parentId = null,
97+
plannerFactory = GoapPlannerFactory,
10298
)
10399
val agentStatus = agentProcess.tick()
104100
assertEquals(AgentProcessStatusCode.WAITING, agentStatus.status)
@@ -117,6 +113,7 @@ class ConcurrentAgentProcessTest {
117113
blackboard = blackboard,
118114
platformServices = dummyPlatformServices,
119115
parentId = null,
116+
plannerFactory = GoapPlannerFactory,
120117
)
121118
val agentStatus = agentProcess.run()
122119
assertEquals(AgentProcessStatusCode.WAITING, agentStatus.status)
@@ -191,6 +188,7 @@ class ConcurrentAgentProcessTest {
191188
blackboard = blackboard,
192189
platformServices = dummyPlatformServices,
193190
parentId = null,
191+
plannerFactory = GoapPlannerFactory,
194192
)
195193
return agentProcess.run()
196194
}
@@ -211,6 +209,7 @@ class ConcurrentAgentProcessTest {
211209
processOptions = ProcessOptions(),
212210
blackboard = blackboard,
213211
platformServices = dummyPlatformServices,
212+
plannerFactory = GoapPlannerFactory,
214213
parentId = null,
215214
)
216215
val person = LocalPerson("John")
@@ -229,6 +228,7 @@ class ConcurrentAgentProcessTest {
229228
processOptions = ProcessOptions(),
230229
blackboard = blackboard,
231230
platformServices = dummyPlatformServices,
231+
plannerFactory = GoapPlannerFactory,
232232
parentId = null,
233233
)
234234
val person = LocalPerson("John")
@@ -246,6 +246,7 @@ class ConcurrentAgentProcessTest {
246246
processOptions = ProcessOptions(),
247247
blackboard = blackboard,
248248
platformServices = dummyPlatformServices,
249+
plannerFactory = GoapPlannerFactory,
249250
parentId = null,
250251
)
251252
val person = LocalPerson("John")
@@ -264,6 +265,7 @@ class ConcurrentAgentProcessTest {
264265
processOptions = ProcessOptions(),
265266
blackboard = blackboard,
266267
platformServices = dummyPlatformServices,
268+
plannerFactory = GoapPlannerFactory,
267269
parentId = null,
268270
)
269271
val person = LocalPerson("John")
@@ -290,6 +292,7 @@ class ConcurrentAgentProcessTest {
290292
processOptions = ProcessOptions(),
291293
blackboard = blackboard,
292294
platformServices = dummyPlatformServices,
295+
plannerFactory = GoapPlannerFactory,
293296
parentId = null,
294297
)
295298
assertEquals(0, agentProcess.toolsStats.toolsStats.size, "No tools called yet")
@@ -310,6 +313,7 @@ class ConcurrentAgentProcessTest {
310313
processOptions = ProcessOptions(),
311314
blackboard = blackboard,
312315
platformServices = dummyPlatformServices,
316+
plannerFactory = GoapPlannerFactory,
313317
parentId = null,
314318
)
315319
assertEquals(AgentProcessStatusCode.NOT_STARTED, agentProcess.status)

0 commit comments

Comments
 (0)