You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ofbiz.apache.org by "Anil K Patel (Jira)" <ji...@apache.org> on 2026/06/02 10:36:00 UTC
[jira] [Updated] (OFBIZ-13408) New Plugin: ai - Agent Framework for LLM Integration
[ https://issues.apache.org/jira/browse/OFBIZ-13408?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Anil K Patel updated OFBIZ-13408:
---------------------------------
Description:
h2. Summary
New optional plugin ({{plugins/ai}}) that brings native AI agent capabilities to OFBiz — callable from any service, screen action, or scheduled job. No external AI SDK required.
h2. Motivation
AI/LLM capabilities are increasingly essential in enterprise applications. OFBiz currently has no built-in way to call AI providers from services. Developers who need AI in their OFBiz implementations must build this infrastructure themselves, each time, without consistency.
This plugin provides a reusable, convention-following integration that any OFBiz deployment can install without modifying framework code.
h2. Design
The plugin follows established OFBiz patterns throughout. The original design used LangChain4j; after initial smoke testing, LangChain4j was removed. Its functionality required fewer than 300 lines of direct HTTP code and would have added 15+ MB of transitive dependencies to the OFBiz runtime. The plugin now uses {{java.net.http.HttpClient}} and Jackson — both already present in the OFBiz runtime. No external AI SDK.
h3. Lifecycle — Container interface
Implements the Container interface for lifecycle management, same pattern as BirtContainer in the birt plugin. Registered in ofbiz-component.xml:
{code}
<container name="ai-container" loaders="main"
class="org.apache.ofbiz.ai.container.AiContainer"/>
{code}
AiContainer.start() loads all provider, tool, and agent registries from XML files across all components. AiContainer.stop() cleanly shuts down.
h3. Configuration — ai.properties
Named provider blocks via config/ai.properties, read with UtilProperties:
{code}
ai.provider.openai-default.baseUrl=https://api.openai.com/v1
ai.provider.openai-default.apiKey=...
ai.provider.openai-default.model=gpt-4o
ai.provider.openai-default.timeout=60
ai.provider.anthropic-default.baseUrl=https://api.anthropic.com/v1
ai.provider.anthropic-default.apiKey=...
ai.provider.anthropic-default.model=claude-sonnet-4-5
ai.provider.anthropic-default.timeout=60
ai.provider.anthropic-default.extraHeaders=anthropic-version:2023-06-01
ai.provider.ollama-default.baseUrl=http://localhost:11434/v1
ai.provider.ollama-default.model=llama3.2
{code}
Any OpenAI-compatible endpoint is supported. Provider selection is configuration-only — no code change required.
h3. Declarative agents and tools — XML
Developers declare tools (OFBiz services) and agents in XML files placed in any component’s {{ai/}} directory. ToolCatalog and AgentRegistry scan all components at startup.
*tools.xml* — exposes any OFBiz service as an AI tool:
{code:xml}
<tools>
<tool name="getMrpRecommendation"
service-name="getMrpRecommendation"
description="Gets MRP recommendations for a product facility"
required-permission="MANUFACTURING_VIEW"
requires-approval="false"/>
</tools>
{code}
*agent.xml* — declares an agent with provider, system prompt, and tool allow-list:
{code:xml}
<agents>
<agent name="mrp-advisor" provider="openai-default" max-iterations="6">
<system-prompt>You are an MRP advisor for a manufacturing company...</system-prompt>
<tools>
<tool name="getMrpRecommendation"/>
</tools>
</agent>
</agents>
{code}
Adding a new tool or agent requires only XML — no Java changes.
h3. Services
Single service entry point:
{code}
agentRun(agentName, userMessage, userLogin)
optional IN: threadId, approvalRequired
OUT: assistantMessage, stopReason, iterationsUsed, threadId, proposalId
{code}
Supporting services:
{code}
getUsageSummary(agentName?, userLoginId?, fromDate?, thruDate?)
OUT: totalRuns, totalInputTokens, totalOutputTokens, estimatedCostUsd
getConversationHistory(threadId) → ordered message list
archiveConversationThread(threadId)
approveAgentProposal(proposalId) → resumes agent loop, returns final answer
rejectAgentProposal(proposalId, rejectionReason) → LLM acknowledgment
{code}
h3. Database entities
Persistent audit trail for every run:
|| Entity || Purpose ||
| AiAgentRun | Every agentRun invocation — agent, user, tokens, status, messages |
| AiAgentToolCall | Every tool call within a run — arguments, result, timing |
| AiProviderCost | Cost-per-million-token rates by model for cost estimation |
| AiConversationThread | Named multi-turn conversation threads |
| AiConversationMessage | Individual messages within a thread (ordered by sequenceNum) |
| AiAgentProposal | Suspended runs awaiting human approval — full conversation state |
| AiAgentProposalTool | Individual tool calls within a pending proposal |
h3. Security
Tool execution is gated by the OFBiz permission model. Each tool declares a {{required-permission}} in its XML. Calls without sufficient permission fail gracefully — the LLM receives an error and continues reasoning.
Tools can declare {{requires-approval="true"}} for irreversible actions. The agent suspends mid-run, persists the full conversation state as an AiAgentProposal, and returns a {{proposalId}}. A human calls {{approveAgentProposal}} (which executes the tools and resumes the loop) or {{rejectAgentProposal}} (which returns a graceful LLM acknowledgment).
h3. Admin webapp at /ai
Full OFBiz web application mounted at {{/ai}} with six screens:
* *Agent List* — all registered agents; launch an interactive agent run
* *Run History* — paginated AiAgentRun list with filter by agent/user/status/date
* *Run Detail* — single run view with embedded tool-call list
* *Usage Dashboard* — aggregated token and estimated cost summary with filter
* *Proposal Review* — pending proposals with one-click Approve or Reject
* *Thread Explorer* — conversation thread list; message history view; archive action
Permission model: {{OFBTOOLS _VIEW}} for read; {{OFBTOOLS _UPDATE}} for approve/reject.
h3. Testing
{{testdef/AgentRunnerTest.java}} uses {{MockAiChatClient}} to test the agent loop, tool dispatch, result truncation, and max-iterations stop — no network, no API key required.
h2. What this does NOT do
- Does not modify any framework code
- Does not affect OFBiz if plugin is not installed
- Does not add any required dependencies to the framework
- Does not hardcode any specific AI provider
h2. Dependencies
None. Uses only {{java.net.http.HttpClient}} and Jackson, both already present in the OFBiz runtime.
h2. Plugin structure
{code}
plugins/ai/
├── ofbiz-component.xml
├── build.gradle
├── config/ai.properties + AiUiLabels.xml
├── servicedef/services.xml
├── entitydef/AiAgentEntities.xml
├── data/AiAgentSeedData.xml
├── ai/sample.tools.xml + sample.agent.xml
├── src/main/java/org/apache/ofbiz/ai/
│ ├── container/AiContainer.java
│ ├── agent/ProviderRegistry.java, ProviderConfig.java
│ ├── agent/ToolDescriptor.java, ToolCatalog.java
│ ├── agent/AgentDefinition.java, AgentRegistry.java
│ ├── agent/AiChatClient.java, AiHttpClient.java, MockAiChatClient.java
│ ├── agent/AgentRunner.java
│ └── AiWorker.java, AiServices.java, AiAgentServices.java
├── groovyScripts/
│ ├── AiTest.groovy, AiStructuredTest.groovy
│ ├── GetUsageSummary.groovy, GetConversationHistory.groovy
│ └── GetAgentList.groovy
├── testdef/AgentRunnerTest.java
└── webapp/ai/
├── WEB-INF/controller.xml + web.xml
├── index.jsp
└── widget/ai/CommonScreens.xml, AiMenus.xml, AiScreens.xml, AiForms.xml
{code}
h2. Development
Development branch: [patelanil/ofbiz-plugins — feature/ai-plugin|https://github.com/patelanil/ofbiz-plugins/tree/feature/ai-plugin]
Full documentation: [OFBiz AI Plugin — Agent Framework for LLM Integration|https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=430407963]
Java 17 minimum (OFBiz trunk requirement).
was:
## Summary
Add a new optional plugin (plugins/ai) that integrates LangChain4j to bring
native AI/LLM capabilities to OFBiz services, Groovy scripts, and screen actions.
## Motivation
AI/LLM capabilities are increasingly essential in enterprise applications.
OFBiz currently has no built-in way to call AI providers from services.
Developers who need AI in their OFBiz implementations must build this
infrastructure themselves, each time, without consistency.
This plugin provides a reusable, convention-following integration that any
OFBiz deployment can install without modifying framework code.
## Design
The plugin follows established OFBiz patterns throughout:
### Lifecycle — Container interface
Implements the Container interface for lifecycle management, same pattern
as BirtContainer in the birt plugin. Registered in ofbiz-component.xml:
<container name="ai-container" loaders="main"
class="org.apache.ofbiz.ai.container.AiContainer"/>
AiContainer.start() reads configuration, initializes LangChain4j ChatModel
clients, and stores them via AiFactory (same pattern as BirtFactory).
AiContainer.stop() cleanly destroys all clients.
### Configuration — ai.properties
Configuration via config/ai.properties, read with UtilProperties:
ai.provider=openai
ai.model=gpt-4o-mini
ai.baseUrl=
ai.apiKey=
ai.timeout=60
Multiple named configurations are supported for multi-provider setups.
### Services — callable from any service definition
Two OFBiz services exposed via servicedef/services.xml:
ai.generate — List messages → String response
ai.generateStructured — List messages + Map schema → Map result
Callable from any service, screen action, or scheduled job via dispatcher:
Map result = dispatcher.runSync("ai.generate",
UtilMisc.toMap("messages", messages, "userLogin", userLogin))
### Utility class — AiWorker
Static utility for programmatic use in Java and Groovy service implementations,
parallel to BirtWorker:
String response = AiWorker.generate(dctx, messages)
Map result = AiWorker.generateStructured(dctx, messages, schema)
### Structured output schema
Schema uses JSON Schema vocabulary — provider-agnostic, no Java class names:
Map schema = UtilMisc.toMap(
"status", UtilMisc.toMap("type", "string"),
"amount", UtilMisc.toMap("type", "number"),
"approved", UtilMisc.toMap("type", "boolean")
)
## What this does NOT do
- Does not modify any framework code
- Does not affect OFBiz if plugin is not installed
- Does not add any required dependencies to the framework
- Does not hardcode any specific AI provider
## Dependencies
Both are Apache 2.0 licensed:
- dev.langchain4j:langchain4j:1.8.0
- dev.langchain4j:langchain4j-open-ai:1.8.0
LangChain4j supports OpenAI, Anthropic, Ollama, Groq, and any
OpenAI-compatible endpoint. Provider selection is configuration-only.
## Plugin structure
plugins/ai/
├── ofbiz-component.xml
├── config/
│ └── ai.properties
├── servicedef/
│ └── services.xml
├── src/main/java/org/apache/ofbiz/ai/
│ ├── container/AiContainer.java
│ ├── AiFactory.java
│ ├── services/AiServices.java
│ └── util/AiWorker.java
└── build.gradle
## Implementation
Development branch:
https://github.com/patelanil/ofbiz-plugins/tree/feature/ai-plugin
Java 17 minimum (OFBiz trunk requirement).
LangChain4j 1.8.0 (Java 17 compatible, Apache 2.0).
> New Plugin: ai - Agent Framework for LLM Integration
> ----------------------------------------------------
>
> Key: OFBIZ-13408
> URL: https://issues.apache.org/jira/browse/OFBIZ-13408
> Project: OFBiz
> Issue Type: New Feature
> Components: plugin
> Reporter: Anil K Patel
> Assignee: Anil K Patel
> Priority: Trivial
>
> h2. Summary
> New optional plugin ({{plugins/ai}}) that brings native AI agent capabilities to OFBiz — callable from any service, screen action, or scheduled job. No external AI SDK required.
> h2. Motivation
> AI/LLM capabilities are increasingly essential in enterprise applications. OFBiz currently has no built-in way to call AI providers from services. Developers who need AI in their OFBiz implementations must build this infrastructure themselves, each time, without consistency.
> This plugin provides a reusable, convention-following integration that any OFBiz deployment can install without modifying framework code.
> h2. Design
> The plugin follows established OFBiz patterns throughout. The original design used LangChain4j; after initial smoke testing, LangChain4j was removed. Its functionality required fewer than 300 lines of direct HTTP code and would have added 15+ MB of transitive dependencies to the OFBiz runtime. The plugin now uses {{java.net.http.HttpClient}} and Jackson — both already present in the OFBiz runtime. No external AI SDK.
> h3. Lifecycle — Container interface
> Implements the Container interface for lifecycle management, same pattern as BirtContainer in the birt plugin. Registered in ofbiz-component.xml:
> {code}
> <container name="ai-container" loaders="main"
> class="org.apache.ofbiz.ai.container.AiContainer"/>
> {code}
> AiContainer.start() loads all provider, tool, and agent registries from XML files across all components. AiContainer.stop() cleanly shuts down.
> h3. Configuration — ai.properties
> Named provider blocks via config/ai.properties, read with UtilProperties:
> {code}
> ai.provider.openai-default.baseUrl=https://api.openai.com/v1
> ai.provider.openai-default.apiKey=...
> ai.provider.openai-default.model=gpt-4o
> ai.provider.openai-default.timeout=60
> ai.provider.anthropic-default.baseUrl=https://api.anthropic.com/v1
> ai.provider.anthropic-default.apiKey=...
> ai.provider.anthropic-default.model=claude-sonnet-4-5
> ai.provider.anthropic-default.timeout=60
> ai.provider.anthropic-default.extraHeaders=anthropic-version:2023-06-01
> ai.provider.ollama-default.baseUrl=http://localhost:11434/v1
> ai.provider.ollama-default.model=llama3.2
> {code}
> Any OpenAI-compatible endpoint is supported. Provider selection is configuration-only — no code change required.
> h3. Declarative agents and tools — XML
> Developers declare tools (OFBiz services) and agents in XML files placed in any component’s {{ai/}} directory. ToolCatalog and AgentRegistry scan all components at startup.
> *tools.xml* — exposes any OFBiz service as an AI tool:
> {code:xml}
> <tools>
> <tool name="getMrpRecommendation"
> service-name="getMrpRecommendation"
> description="Gets MRP recommendations for a product facility"
> required-permission="MANUFACTURING_VIEW"
> requires-approval="false"/>
> </tools>
> {code}
> *agent.xml* — declares an agent with provider, system prompt, and tool allow-list:
> {code:xml}
> <agents>
> <agent name="mrp-advisor" provider="openai-default" max-iterations="6">
> <system-prompt>You are an MRP advisor for a manufacturing company...</system-prompt>
> <tools>
> <tool name="getMrpRecommendation"/>
> </tools>
> </agent>
> </agents>
> {code}
> Adding a new tool or agent requires only XML — no Java changes.
> h3. Services
> Single service entry point:
> {code}
> agentRun(agentName, userMessage, userLogin)
> optional IN: threadId, approvalRequired
> OUT: assistantMessage, stopReason, iterationsUsed, threadId, proposalId
> {code}
> Supporting services:
> {code}
> getUsageSummary(agentName?, userLoginId?, fromDate?, thruDate?)
> OUT: totalRuns, totalInputTokens, totalOutputTokens, estimatedCostUsd
> getConversationHistory(threadId) → ordered message list
> archiveConversationThread(threadId)
> approveAgentProposal(proposalId) → resumes agent loop, returns final answer
> rejectAgentProposal(proposalId, rejectionReason) → LLM acknowledgment
> {code}
> h3. Database entities
> Persistent audit trail for every run:
> || Entity || Purpose ||
> | AiAgentRun | Every agentRun invocation — agent, user, tokens, status, messages |
> | AiAgentToolCall | Every tool call within a run — arguments, result, timing |
> | AiProviderCost | Cost-per-million-token rates by model for cost estimation |
> | AiConversationThread | Named multi-turn conversation threads |
> | AiConversationMessage | Individual messages within a thread (ordered by sequenceNum) |
> | AiAgentProposal | Suspended runs awaiting human approval — full conversation state |
> | AiAgentProposalTool | Individual tool calls within a pending proposal |
> h3. Security
> Tool execution is gated by the OFBiz permission model. Each tool declares a {{required-permission}} in its XML. Calls without sufficient permission fail gracefully — the LLM receives an error and continues reasoning.
> Tools can declare {{requires-approval="true"}} for irreversible actions. The agent suspends mid-run, persists the full conversation state as an AiAgentProposal, and returns a {{proposalId}}. A human calls {{approveAgentProposal}} (which executes the tools and resumes the loop) or {{rejectAgentProposal}} (which returns a graceful LLM acknowledgment).
> h3. Admin webapp at /ai
> Full OFBiz web application mounted at {{/ai}} with six screens:
> * *Agent List* — all registered agents; launch an interactive agent run
> * *Run History* — paginated AiAgentRun list with filter by agent/user/status/date
> * *Run Detail* — single run view with embedded tool-call list
> * *Usage Dashboard* — aggregated token and estimated cost summary with filter
> * *Proposal Review* — pending proposals with one-click Approve or Reject
> * *Thread Explorer* — conversation thread list; message history view; archive action
> Permission model: {{OFBTOOLS _VIEW}} for read; {{OFBTOOLS _UPDATE}} for approve/reject.
> h3. Testing
> {{testdef/AgentRunnerTest.java}} uses {{MockAiChatClient}} to test the agent loop, tool dispatch, result truncation, and max-iterations stop — no network, no API key required.
> h2. What this does NOT do
> - Does not modify any framework code
> - Does not affect OFBiz if plugin is not installed
> - Does not add any required dependencies to the framework
> - Does not hardcode any specific AI provider
> h2. Dependencies
> None. Uses only {{java.net.http.HttpClient}} and Jackson, both already present in the OFBiz runtime.
> h2. Plugin structure
> {code}
> plugins/ai/
> ├── ofbiz-component.xml
> ├── build.gradle
> ├── config/ai.properties + AiUiLabels.xml
> ├── servicedef/services.xml
> ├── entitydef/AiAgentEntities.xml
> ├── data/AiAgentSeedData.xml
> ├── ai/sample.tools.xml + sample.agent.xml
> ├── src/main/java/org/apache/ofbiz/ai/
> │ ├── container/AiContainer.java
> │ ├── agent/ProviderRegistry.java, ProviderConfig.java
> │ ├── agent/ToolDescriptor.java, ToolCatalog.java
> │ ├── agent/AgentDefinition.java, AgentRegistry.java
> │ ├── agent/AiChatClient.java, AiHttpClient.java, MockAiChatClient.java
> │ ├── agent/AgentRunner.java
> │ └── AiWorker.java, AiServices.java, AiAgentServices.java
> ├── groovyScripts/
> │ ├── AiTest.groovy, AiStructuredTest.groovy
> │ ├── GetUsageSummary.groovy, GetConversationHistory.groovy
> │ └── GetAgentList.groovy
> ├── testdef/AgentRunnerTest.java
> └── webapp/ai/
> ├── WEB-INF/controller.xml + web.xml
> ├── index.jsp
> └── widget/ai/CommonScreens.xml, AiMenus.xml, AiScreens.xml, AiForms.xml
> {code}
> h2. Development
> Development branch: [patelanil/ofbiz-plugins — feature/ai-plugin|https://github.com/patelanil/ofbiz-plugins/tree/feature/ai-plugin]
> Full documentation: [OFBiz AI Plugin — Agent Framework for LLM Integration|https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=430407963]
> Java 17 minimum (OFBiz trunk requirement).
--
This message was sent by Atlassian Jira
(v8.20.10#820010)