embabel-agent
Frameworkembabel/embabel-agent
JVM agent framework blending LLM interactions with code and domain models.
Overview
Embabel is a JVM framework for authoring agentic AI flows that combine LLM-prompted interactions with code and domain models. It features sophisticated dynamic planning, strong typing, Spring integration, and supports both annotation-based and Kotlin DSL authoring styles.
README Preview
# [Embabel Agent Framework](https://hub.embabel.com)\n\n\n\n[](https://docs.embabel.com/embabel-agent/guide/1.5.0-SNAPSHOT/)\n[](https://mvnrepository.com/artifact/com.embabel.agent/embabel-agent-api)\n\n[](https://www.yourkit.com/)\n[](https://www.ej-technologies.com/products/jprofiler/overview.html)\n[](https://sonarcloud.io/summary/new_code?id=embabel_embabel-agent)\n[](https://discord.gg/t6bjkyj93q)\n\n[//]: # ([](https://sonarcloud.io/summary/new_code?id=embabel_embabel-agent))\n\n[//]: # ([](https://sonarcloud.io/summary/new_code?id=embabel_embabel-agent))\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n[](https://www.apache.org/licenses/LICENSE-2.0)\n[](https://github.com/embabel/embabel-agent/pulse)\n\n \n\nEmbabel (Em-BAY-bel) is a framework for authoring agentic flows on the JVM that seamlessly mix LLM-prompted interactions\nwith code and domain models. Supports\nintelligent path finding towards goals. Written in Kotlin\nbut offers a natural usage\nmodel from Java.\nFrom the creator of Spring.\n\n \n\n## Talk to the Docs\n\nHave questions? [Talk to the docs via the Embabel-powered hub](https://hub.embabel.com) — an\nEmbabel agent that answers your questions about the framework in natural language.\n\n## Key Concepts\n\nModels agentic flows in terms of:\n\n- **Actions**: Steps an agent takes\n- **Goals**: What an agent is trying to achieve\n- **Conditions**: Conditions to assess before executing an action or determining that a goal has been achieved.\n Conditions are reassessed after each action is executed.\n- **Domain model**: Objects underpinning the flow and informing Actions, Goals and Conditions.\n- **Plan**: A sequence of actions to achieve a goa
FAQ (5)
TroubleshootingHow to fix a returned Tool.Result.Error being recorded and counted as a successful ToolCallResponseEvent?
The failure occurs because EventPublishingTool maps only thrown exceptions to Result.failure; a returned Tool.Result.Error follows the success branch and is published as Result.success("<error message>"). Fix EventPublishingTool in ToolDecorators.kt so that when the delegate returns Tool.Result.Error, it publishes Result.failure(ToolReturnedError(message, cause)) while call() still returns the original Error. Do not change the returned intermediate result, because downstream recovery and Spring's ToolExecutionException conversion depend on it. Add a test where the delegate returns Tool.Result.Error, asserting both that responseEvent.result.isFailure is true and that call() still returns the original Error. This makes result.isFailure, tool stats, and embabel.tool.errors.total report the call correctly. Until using a release containing the fix, custom tools can throw instead of returning Tool.Result.Error, but annotated MethodTool and ScriptTool errors require the patch.
TroubleshootingHow to fix missing newer OpenAI models (for example gpt-5.6-luna) when using Embabel LM Studio autoconfigure?
This happens because embabel-agent-lmstudio-autoconfigure contains a stale duplicate models/openai-models.yml. If that JAR loads first, OpenAiModelLoader uses it instead of the catalog in embabel-agent-openai-autoconfigure, so newer models are never registered.
Fix:
1. Upgrade to a release containing the fix for issue #2064, where the duplicate file was removed from embabel-agent-lmstudio-autoconfigure.
2. As a temporary workaround, remove the stale resource from the LM Studio JAR:
jar tf embabel-agent-lmstudio-autoconfigure-*.jar | grep 'models/openai-models.yml'
zip -d embabel-agent-lmstudio-autoconfigure-*.jar 'models/openai-models.yml'Rebuild and repackage the application afterward. Alternatively, ensure
embabel-agent-openai-autoconfigure appears before the LM Studio JAR on the classpath, although JAR/classpath ordering can be fragile.3. Verify startup logging. With the correct catalog loaded, you should see entries such as:
Registered OpenAI model bean: gpt56luna -> gpt-5.6-luna
A longer-term safeguard is to have OpenAiModelLoader call getResources("models/openai-models.yml") and warn or fail when multiple catalog copies are found.
TroubleshootingWhy does my Embabel agent show version 0.1.0-SNAPSHOT instead of the application build version?
Agents declared without an explicit @Agent(version = "...") previously fell back to the framework default 0.1.0-SNAPSHOT, because annotations require compile-time constants and cannot read the Maven/Gradle project version. Fixed in PR #2113 via an AgentVersionResolver used by AgentMetadataReader, which resolves the version in this order: 1) Explicit @Agent(version = "...") if set; 2) Spring Boot BuildProperties.version when build-info is generated; 3) the JAR manifest Implementation-Version of the agent class package; 4) Semver.DEFAULT_VERSION as final fallback. To get your build version into agent metadata, either set the version explicitly: @Agent(description = "...", version = "2.0.0"), or enable Spring Boot build-info generation. For Maven: add an execution of the build-info goal to spring-boot-maven-plugin. For Gradle: add springBoot { buildInfo() }. Then the deployed agent metadata will reflect the actual application artifact version.
TroubleshootingHow to migrate an Embabel MCP server from deprecated SSE to Streamable HTTP with Spring AI 2.0?
Use an Embabel release that includes the MCP Streamable HTTP migration, where the SSE-only McpSseShutdownConfiguration is removed and WebMvcSseServerTransportProvider is no longer used. Then let Spring AI auto-configuration select the transport by adding:
spring.ai.mcp.server.protocol=STREAMABLE
or YAML:
spring:
ai:
mcp:
server:
protocol: STREAMABLE
Remove any custom beans or configuration referencing WebMvcSseServerTransportProvider, McpSseShutdownConfiguration, or the legacy SSE endpoint. Rebuild with ./mvnw clean package. Remote MCP or agent-to-agent clients must connect to the Streamable HTTP endpoint rather than the old SSE endpoint. On versions containing this change, Embabel delegates transport handling to Spring AI and no longer retains the SSE-specific shutdown code path.
TroubleshootingHow do I increase the timeout for a slow local OpenAI-compatible or Docker embedding model?
Upgrade to a release containing the fix for issue #2083, then configure connect-timeout and read-timeout instead of relying on the hard-coded client defaults. For Docker Model Runner, set, for example:
embabel:
agent:
platform:
models:
docker:
connect-timeout: 5s
read-timeout: 30m
For a generic OpenAI-compatible provider, set the same connect-timeout and read-timeout properties in that provider's configuration. The patched implementation applies the values to both embedding and completion/chat clients and propagates them to Spring AI's per-request options, which otherwise send a 60-second timeout and override the HTTP client setting. Defaults remain 5 seconds for connect and 10 minutes for read. On older versions, the only workaround is to reduce the embedding batch size, e.g. split an 800-chunk request into smaller requests.