From 90183b601bcd07371af36719fc6d601441235670 Mon Sep 17 00:00:00 2001 From: Slava Imeshev Date: Mon, 13 Jul 2026 15:45:15 -0700 Subject: [PATCH 1/5] #1741 - enhancement: improve agent registration failure messages and empty shell listing. Signed-off-by: Slava Imeshev --- .../annotation/support/AgentMetadataReader.kt | 25 ++- .../core/support/AbstractAgentProcess.kt | 2 +- .../AgentMetadataReaderMetadataTest.kt | 27 +++ .../agent/api/annotation/support/testTypes.kt | 13 ++ .../com/embabel/agent/shell/ShellCommands.kt | 15 +- .../agent/shell/ShellCommandsAgentsTest.kt | 201 ++++++++++++++++++ 6 files changed, 266 insertions(+), 17 deletions(-) create mode 100644 embabel-agent-shell/src/test/kotlin/com/embabel/agent/shell/ShellCommandsAgentsTest.kt diff --git a/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReader.kt b/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReader.kt index 13723d488..ae34d51d8 100644 --- a/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReader.kt +++ b/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReader.kt @@ -216,8 +216,9 @@ class AgentMetadataReader( } if (actionMethods.isEmpty() && goals.isEmpty() && conditionMethods.isEmpty()) { - logger.warn( - "❓No methods annotated with @{} or @{} and no goals defined on {}", + logger.warn("❓{} {} is not registered due to no methods annotated with @{} or @{} and no goals defined on {}", + if (agenticInfo.isAgent()) "Agent" else "Agentic component", + agenticInfo.agentName(), Action::class.simpleName, Condition::class.simpleName, targetType.name, @@ -230,15 +231,16 @@ class AgentMetadataReader( if (plannerType == PlannerType.SUPERVISOR) { // Find the goal action (the action with @AchievesGoal) if (goalActions.isEmpty()) { - logger.warn( - "SUPERVISOR planner requires at least one @AchievesGoal action on {}", + logger.warn("❓Agent {} is not registered: SUPERVISOR planner requires at least one @AchievesGoal action on {}", + agenticInfo.agentName(), targetType.name, ) return null } if (goalActions.size > 1) { logger.warn( - "SUPERVISOR planner currently supports only one @AchievesGoal action, found {} on {}", + "❓Agent {} is not registered: SUPERVISOR planner currently supports only one @AchievesGoal action, found {} on {}", + agenticInfo.agentName(), goalActions.size, targetType.name, ) @@ -264,8 +266,8 @@ class AgentMetadataReader( val typeNames = distinctGoalTypes.joinToString { it.simpleName.ifEmpty { it.name } } if (restrictedGoals) { logger.warn( - "Agent {} has @AchievesGoal actions returning distinct types [{}] - rejected. Set embabel.agent.platform.planner.restricted-goals=false to allow", - targetType.name, + "❓Agent {} is not registered due to @AchievesGoal actions returning distinct types [{}]. Set embabel.agent.platform.planner.restricted-goals=false to allow", + agenticInfo.agentName(), typeNames, ) return null @@ -303,9 +305,12 @@ class AgentMetadataReader( if (plannerType == PlannerType.GOAP && agenticInfo.isAgent()) { val validationResult = agentValidationManager.validate(agent) if (!validationResult.isValid) { - logger.warn("Agent validation failed:\n${validationResult.errors.joinToString("\n")}") - // TODO: Uncomment to strengthen validation and refactor the test if needed. Because some tests might fail. - // return null + logger.warn( + "❓Agent {} is not registered due to validation failure:\n{}", + agent.name, + validationResult.errors.joinToString("\n"), + ) + return null } } diff --git a/embabel-agent-api/src/main/kotlin/com/embabel/agent/core/support/AbstractAgentProcess.kt b/embabel-agent-api/src/main/kotlin/com/embabel/agent/core/support/AbstractAgentProcess.kt index e0370a136..0cce9129a 100644 --- a/embabel-agent-api/src/main/kotlin/com/embabel/agent/core/support/AbstractAgentProcess.kt +++ b/embabel-agent-api/src/main/kotlin/com/embabel/agent/core/support/AbstractAgentProcess.kt @@ -341,7 +341,7 @@ abstract class AbstractAgentProcess( */ private fun executeTurn(): AgentProcess { if (agent.goals.isEmpty() && processOptions.plannerType.needsGoals) { - logger.info("🛑 Process {} has no goals: {}", this.id, agent.goals) + logger.error("🛑 Process {} has no goals", this.id) error("Agent ${agent.name} has no goals: ${agent.infoString(verbose = true)}") } diff --git a/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReaderMetadataTest.kt b/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReaderMetadataTest.kt index e5908f3f4..6686f962e 100644 --- a/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReaderMetadataTest.kt +++ b/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReaderMetadataTest.kt @@ -27,6 +27,9 @@ import org.junit.jupiter.api.Assertions.* import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.boot.test.system.CapturedOutput +import org.springframework.boot.test.system.OutputCaptureExtension import kotlin.test.assertNull import com.embabel.agent.core.Agent as CoreAgent @@ -35,6 +38,7 @@ import com.embabel.agent.core.Agent as CoreAgent * Test for metadata extraction from annotations, * not invocation */ +@ExtendWith(OutputCaptureExtension::class) class AgentMetadataReaderMetadataTest { @Nested @@ -53,6 +57,29 @@ class AgentMetadataReaderMetadataTest { assertNull(reader.createAgentMetadata(NoMethods())) } + @Test + fun `agent with no methods is not registered and logs explicit warning`(output: CapturedOutput) { + val reader = AgentMetadataReader() + assertNull(reader.createAgentMetadata(AgentWithNoMethods())) + assertTrue( + output.all.contains("AgentWithNoMethods is not registered"), + "Expected explicit not-registered warning, got: ${output.all}", + ) + } + + @Test + fun `agent that fails structure validation is not registered`(output: CapturedOutput) { + val reader = AgentMetadataReader() + assertNull( + reader.createAgentMetadata(AgentWithGoalButNoActions()), + "Agent with goals but no actions must not be registered (issue #1741)", + ) + assertTrue( + output.all.contains("is not registered"), + "Expected not-registered warning for validation failure, got: ${output.all}", + ) + } + @Test @Disabled fun invalidConditionSignature() { diff --git a/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/testTypes.kt b/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/testTypes.kt index c7ed7f3e9..cf096cbb5 100644 --- a/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/testTypes.kt +++ b/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/testTypes.kt @@ -54,6 +54,19 @@ data class PersonWithReverseTool(val name: String) { @EmbabelComponent class NoMethods +@Agent(description = "agent with no actions, conditions, or goals") +class AgentWithNoMethods + +@Agent(description = "agent with a goal property but no actions") +class AgentWithGoalButNoActions { + + val orphanGoal = Goal.createInstance( + name = "orphanGoal", + description = "Goal with no path because there are no actions", + type = PersonWithReverseTool::class.java, + ) +} + @EmbabelComponent class OneGoalOnly { diff --git a/embabel-agent-shell/src/main/kotlin/com/embabel/agent/shell/ShellCommands.kt b/embabel-agent-shell/src/main/kotlin/com/embabel/agent/shell/ShellCommands.kt index 5c2859b2d..48911dbbc 100644 --- a/embabel-agent-shell/src/main/kotlin/com/embabel/agent/shell/ShellCommands.kt +++ b/embabel-agent-shell/src/main/kotlin/com/embabel/agent/shell/ShellCommands.kt @@ -189,13 +189,16 @@ class ShellCommands( @ShellMethod("List agents") fun agents(): String { + val agents = agentPlatform.agents() + if (agents.isEmpty()) { + return "No agents registered" + } val detail = "${"Agents:".bold()}\n${ - agentPlatform.agents() - .joinToString(separator = "\n${"-".repeat(shellProperties.lineLength)}\n") { - it.infoString(verbose = true, indent = 1) - } + agents.joinToString(separator = "\n${"-".repeat(shellProperties.lineLength)}\n") { + it.infoString(verbose = true, indent = 1) + } }" - return detail + "\n\nTL;DR\n${agentPlatform.agents().joinToString("\n") { "${it.name}: ${it.description}" }}" + return detail + "\n\nSummary\n${agents.joinToString("\n") { "${it.name}: ${it.description}" }}" } @ShellMethod("List actions") @@ -204,7 +207,7 @@ class ShellCommands( agentPlatform.actions .joinToString(separator = "\n") { it.infoString(verbose = true, indent = 1) } }" - return detail + "\n\nTL;DR\n${agentPlatform.actions.joinToString("\n") { "${it.name}: ${it.description}" }}" + return detail + "\n\nSummary\n${agentPlatform.actions.joinToString("\n") { "${it.name}: ${it.description}" }}" } @ShellMethod("List conditions") diff --git a/embabel-agent-shell/src/test/kotlin/com/embabel/agent/shell/ShellCommandsAgentsTest.kt b/embabel-agent-shell/src/test/kotlin/com/embabel/agent/shell/ShellCommandsAgentsTest.kt new file mode 100644 index 000000000..2033e2af1 --- /dev/null +++ b/embabel-agent-shell/src/test/kotlin/com/embabel/agent/shell/ShellCommandsAgentsTest.kt @@ -0,0 +1,201 @@ +/* + * Copyright 2024-2026 Embabel Pty Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.embabel.agent.shell + +import com.embabel.agent.api.common.ToolsStats +import com.embabel.agent.api.common.autonomy.Autonomy +import com.embabel.agent.api.common.autonomy.AutonomyProperties +import com.embabel.agent.core.Agent +import com.embabel.agent.core.AgentPlatform +import com.embabel.agent.shell.config.ShellProperties +import com.embabel.agent.spi.logging.ColorPalette +import com.embabel.agent.spi.logging.LoggingPersonality +import com.embabel.common.ai.model.ModelProvider +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import io.mockk.every +import io.mockk.mockk +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.springframework.context.ConfigurableApplicationContext +import org.springframework.core.env.ConfigurableEnvironment + +/** + * Regression tests for the agents shell command (issue #1741): + * empty-state messaging and preserved good output when agents exist. + */ +class ShellCommandsAgentsTest { + + private val autonomy: Autonomy = mockk(relaxed = true) + private val modelProvider: ModelProvider = mockk(relaxed = true) + private val terminalServices: TerminalServices = mockk(relaxed = true) + private val environment: ConfigurableEnvironment = mockk(relaxed = true) + private val objectMapper: ObjectMapper = jacksonObjectMapper() + private val colorPalette: ColorPalette = object : ColorPalette { + override val highlight: Int = 0xbeb780 + override val color2: Int = 0x7da17e + } + private val loggingPersonality: LoggingPersonality = mockk(relaxed = true) { + every { logger } returns mockk(relaxed = true) + every { colorPalette } returns this@ShellCommandsAgentsTest.colorPalette + } + private val toolsStats: ToolsStats = mockk(relaxed = true) + private val context: ConfigurableApplicationContext = mockk(relaxed = true) + private val agentPlatform: AgentPlatform = mockk(relaxed = true) + private val autonomyProperties: AutonomyProperties = mockk(relaxed = true) + private val shellProperties = ShellProperties() + + private lateinit var shellCommands: ShellCommands + + @BeforeEach + fun setUp() { + every { autonomy.agentPlatform } returns agentPlatform + every { autonomy.properties } returns autonomyProperties + shellCommands = ShellCommands( + autonomy = autonomy, + modelProvider = modelProvider, + terminalServices = terminalServices, + environment = environment, + objectMapper = objectMapper, + colorPalette = colorPalette, + loggingPersonality = loggingPersonality, + toolsStats = toolsStats, + context = context, + shellProperties = shellProperties, + asyncer = mockk(relaxed = true), + ) + } + + private fun agent( + name: String, + description: String, + provider: String = "test-provider", + ) = Agent( + name = name, + provider = provider, + description = description, + actions = emptyList(), + goals = emptySet(), + ) + + /** Strip ANSI escape codes so assertions ignore bold/color styling. */ + private fun String.stripAnsi(): String = + replace(Regex("\u001B\\[[;\\d]*m"), "") + + @Nested + inner class EmptyAgents { + + @Test + fun `shows no agents registered when platform has no agents`() { + every { agentPlatform.agents() } returns emptyList() + + val result = shellCommands.agents() + + assertEquals("No agents registered", result) + } + } + + @Nested + inner class RegisteredAgents { + + @Test + fun `single agent has detailed listing and summary`() { + val demo = agent(name = "demo-agent", description = "A demo agent") + every { agentPlatform.agents() } returns listOf(demo) + + val result = shellCommands.agents().stripAnsi() + + assertTrue(result.contains("Agents:"), "Expected Agents header, got: $result") + assertTrue(result.contains("description: A demo agent"), "Expected detailed description, got: $result") + assertTrue(result.contains("provider: test-provider"), "Expected provider in detail, got: $result") + assertTrue(result.contains("name: demo-agent"), "Expected name in detail, got: $result") + assertTrue(result.contains("Summary"), "Expected Summary section, got: $result") + assertTrue( + result.contains("demo-agent: A demo agent"), + "Expected name:description summary line, got: $result", + ) + assertTrue( + result.indexOf("Agents:") < result.indexOf("Summary"), + "Detail listing should come before Summary, got: $result", + ) + assertTrue( + result.indexOf("description: A demo agent") < result.indexOf("Summary"), + "Verbose detail should appear before Summary, got: $result", + ) + assertFalse( + result.contains("No agents registered"), + "Should not claim no agents when agents exist: $result", + ) + } + + @Test + fun `multiple agents are separated and all appear in summary`() { + val poet = agent(name = "Poet", description = "Write poems") + val coder = agent(name = "Coder", description = "Answer coding questions") + every { agentPlatform.agents() } returns listOf(poet, coder) + + val result = shellCommands.agents().stripAnsi() + val separator = "-".repeat(shellProperties.lineLength) + + assertTrue(result.contains("description: Write poems"), "Expected Poet detail, got: $result") + assertTrue( + result.contains("description: Answer coding questions"), + "Expected Coder detail, got: $result", + ) + assertTrue( + result.contains(separator), + "Expected separator between agents of length ${shellProperties.lineLength}, got: $result", + ) + assertTrue( + result.indexOf("description: Write poems") < result.indexOf(separator) && + result.indexOf(separator) < result.indexOf("description: Answer coding questions"), + "Separator should sit between agent detail blocks, got: $result", + ) + + val summaryStart = result.indexOf("Summary") + assertTrue(summaryStart >= 0, "Expected Summary section, got: $result") + val summary = result.substring(summaryStart) + assertTrue(summary.contains("Poet: Write poems"), "Expected Poet in summary: $summary") + assertTrue( + summary.contains("Coder: Answer coding questions"), + "Expected Coder in summary: $summary", + ) + assertTrue( + summary.indexOf("Poet: Write poems") < summary.indexOf("Coder: Answer coding questions"), + "Summary should preserve agent order, got: $summary", + ) + } + + @Test + fun `summary is only name and description lines after the Summary header`() { + val agent = agent(name = "demo-agent", description = "A demo agent") + every { agentPlatform.agents() } returns listOf(agent) + + val result = shellCommands.agents().stripAnsi() + val summaryLines = result.substringAfter("Summary").trim().lines() + + assertEquals( + listOf("demo-agent: A demo agent"), + summaryLines, + "Summary should be only concise name:description lines", + ) + } + } +} From 6ea03f11332d15f02a6918dba43f0b537451921e Mon Sep 17 00:00:00 2001 From: Slava Imeshev Date: Mon, 13 Jul 2026 16:32:37 -0700 Subject: [PATCH 2/5] #1741 - text fix: make GOAP retry fixtures use non-nullable action inputs Nullable domain params skip the input precondition, so path validation failed with NO_PATH_TO_GOAL and createAgentMetadata returned null. Keep planner=GOAP; fix RetryActionAnnotationTest and ActionRetryPolicyPropertiesTest fixtures only. Signed-off-by: Slava Imeshev --- .../agent/api/annotation/support/RetryActionAnnotationTest.kt | 2 +- .../agent/spi/config/spring/ActionRetryPolicyPropertiesTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/RetryActionAnnotationTest.kt b/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/RetryActionAnnotationTest.kt index 8616b33ac..570299038 100644 --- a/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/RetryActionAnnotationTest.kt +++ b/embabel-agent-api/src/test/kotlin/com/embabel/agent/api/annotation/support/RetryActionAnnotationTest.kt @@ -87,7 +87,7 @@ internal class AgentWithTwoRetryActions { @AchievesGoal(description = "Process the input") @Action(actionRetryPolicyExpression = "\${retry-twice}") - fun firstAction(input: RetryTestInput?): RetryTestOutput { + fun firstAction(input: RetryTestInput): RetryTestOutput { retryInvocations.incrementAndGet() if (retryInvocations.get() == 1) throw RuntimeException("Failed!") diff --git a/embabel-agent-api/src/test/kotlin/com/embabel/agent/spi/config/spring/ActionRetryPolicyPropertiesTest.kt b/embabel-agent-api/src/test/kotlin/com/embabel/agent/spi/config/spring/ActionRetryPolicyPropertiesTest.kt index 8d6bc023e..958972bc0 100644 --- a/embabel-agent-api/src/test/kotlin/com/embabel/agent/spi/config/spring/ActionRetryPolicyPropertiesTest.kt +++ b/embabel-agent-api/src/test/kotlin/com/embabel/agent/spi/config/spring/ActionRetryPolicyPropertiesTest.kt @@ -174,7 +174,7 @@ internal class JavaAgentWithTwoRetryPropertiesActions { @AchievesGoal(description = "Process the input") @Action(actionRetryPolicyExpression = "\${retry-twice}") - fun perform(input: JavaRetryTestInput?): JavaRetryTestOutput { + fun perform(input: JavaRetryTestInput): JavaRetryTestOutput { retryInvocations.incrementAndGet() if (retryInvocations.get() == 1) throw RuntimeException("Failed!") From a8fe74196c625c88abedb000cec2fd83c2c0617e Mon Sep 17 00:00:00 2001 From: Slava Imeshev Date: Mon, 13 Jul 2026 17:00:57 -0700 Subject: [PATCH 3/5] #1741 - resolved feedback "The test duplicates the existing DefaultColorPalette implementation via an anonymous ColorPalette object. Using DefaultColorPalette directly avoids duplication and keeps the test aligned if the default palette changes." Signed-off-by: Slava Imeshev --- .../com/embabel/agent/shell/ShellCommandsAgentsTest.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/embabel-agent-shell/src/test/kotlin/com/embabel/agent/shell/ShellCommandsAgentsTest.kt b/embabel-agent-shell/src/test/kotlin/com/embabel/agent/shell/ShellCommandsAgentsTest.kt index 2033e2af1..4635cb9ef 100644 --- a/embabel-agent-shell/src/test/kotlin/com/embabel/agent/shell/ShellCommandsAgentsTest.kt +++ b/embabel-agent-shell/src/test/kotlin/com/embabel/agent/shell/ShellCommandsAgentsTest.kt @@ -22,6 +22,7 @@ import com.embabel.agent.core.Agent import com.embabel.agent.core.AgentPlatform import com.embabel.agent.shell.config.ShellProperties import com.embabel.agent.spi.logging.ColorPalette +import com.embabel.agent.spi.logging.DefaultColorPalette import com.embabel.agent.spi.logging.LoggingPersonality import com.embabel.common.ai.model.ModelProvider import com.fasterxml.jackson.databind.ObjectMapper @@ -48,10 +49,7 @@ class ShellCommandsAgentsTest { private val terminalServices: TerminalServices = mockk(relaxed = true) private val environment: ConfigurableEnvironment = mockk(relaxed = true) private val objectMapper: ObjectMapper = jacksonObjectMapper() - private val colorPalette: ColorPalette = object : ColorPalette { - override val highlight: Int = 0xbeb780 - override val color2: Int = 0x7da17e - } + private val colorPalette: ColorPalette = DefaultColorPalette() private val loggingPersonality: LoggingPersonality = mockk(relaxed = true) { every { logger } returns mockk(relaxed = true) every { colorPalette } returns this@ShellCommandsAgentsTest.colorPalette From 4dbb8ba287da742b4d0e7f3c2d8cefae4ccb1c27 Mon Sep 17 00:00:00 2001 From: Slava Imeshev Date: Wed, 15 Jul 2026 09:48:17 -0700 Subject: [PATCH 4/5] #1741 - resolved feedback "agentName() returns the logical name (@Agent(name = "star-wars-fan")), not the class, so the log gives no clue which file to open - and this is the path where the agent gets removed, so we need it most." Signed-off-by: Slava Imeshev --- .../embabel/agent/api/annotation/support/AgentMetadataReader.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReader.kt b/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReader.kt index ae34d51d8..33fea74b2 100644 --- a/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReader.kt +++ b/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReader.kt @@ -307,7 +307,7 @@ class AgentMetadataReader( if (!validationResult.isValid) { logger.warn( "❓Agent {} is not registered due to validation failure:\n{}", - agent.name, + agenticInfo.agentName(), validationResult.errors.joinToString("\n"), ) return null From 594d139a281c19ead3a33f1f5face01e95552c42 Mon Sep 17 00:00:00 2001 From: Slava Imeshev Date: Wed, 15 Jul 2026 11:01:52 -0700 Subject: [PATCH 5/5] #1741 - resolved feedback "AgentMetadataReader.kt:84: + instead of += returns a new list and the result is discarded, so the error is never added. A blank @Agent(description = "") produces no warning at all: validationErrors() comes back empty and the agent registers silently." Signed-off-by: Slava Imeshev --- .../embabel/agent/api/annotation/support/AgentMetadataReader.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReader.kt b/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReader.kt index 33fea74b2..b9def4a04 100644 --- a/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReader.kt +++ b/embabel-agent-api/src/main/kotlin/com/embabel/agent/api/annotation/support/AgentMetadataReader.kt @@ -81,7 +81,7 @@ internal data class AgenticInfo( errors += "Both @Agentic and @Agent annotations found on ${targetType.name}. Treating class as Agent, but both should not be used" } if (agentAnnotation != null && agentAnnotation.description.isBlank()) { - errors + "No description provided for @${Agent::class.java.simpleName} on ${targetType.name}" + errors += "No description provided for @${Agent::class.java.simpleName} on ${targetType.name}" } return errors }