LLM Integration
Version: 6.2.0
Overview
The LLM Lifecycle Task (formerly "Langchain") is EDDI's unified integration point for Large Language Models (LLMs).
By default, it provides simple chat with any LLM provider. Optionally, you can enable agent mode to give your LLM access to built-in tools (calculator, web search, weather, etc.).
EDDI supports 12 LLM providers out of the box: OpenAI, Anthropic, Google Gemini, Mistral AI, Azure OpenAI, Amazon Bedrock, Oracle GenAI, Ollama, Hugging Face, and Jlama — plus any OpenAI-compatible endpoint (DeepSeek, Cohere, etc.) via the baseUrl parameter.
The task automatically detects which mode to use based on your configuration—no manual switching required.
EDDI's Value Proposition for LLMs
EDDI doesn't just forward messages to LLMs—it orchestrates them:
Conditional LLM Invocation: Use Behavior Rules to decide whether to call an LLM based on user input, context, or conversation state
Pre-processing: Parse, normalize, and enrich user input before sending to the LLM
Context Management: Control exactly what conversation history and context data is sent to the LLM
Multi-LLM Support: Switch between different LLMs (OpenAI, Claude, Gemini, Ollama, Hugging Face, Jlama) based on rules or user preferences
Post-processing: Transform, validate, or augment LLM responses before sending to users
Hybrid Workflows: Combine LLM calls with traditional APIs (e.g., LLM generates query → API fetches data → LLM formats result)
State Persistence: All LLM interactions are logged in conversation memory for analytics and debugging
Tool Calling: Enable LLMs to use built-in tools or custom HTTP call tools to access external capabilities
Role in the Lifecycle
The Langchain task is a lifecycle task that executes when triggered by Behavior Rules:
Supported LLM Providers
The Langchain task integrates with multiple LLM providers via the langchain4j library:
OpenAI (ChatGPT, GPT-4, GPT-4o) — also supports DeepSeek and Cohere via
baseUrlAnthropic (Claude)
Google Gemini (
gemini- AI Studio API,gemini-vertex- Vertex AI)Mistral AI (Mistral Large, Codestral, Pixtral)
Azure OpenAI (GPT-4o via Azure-hosted endpoints)
Amazon Bedrock (Claude, Llama, Titan via AWS credential chain)
Oracle GenAI (Cohere Command R+ via OCI authentication)
Ollama (Local models)
Hugging Face (Various models)
Jlama (Local Java-based inference)
Note: Use the "Agent Father" agent to streamline setup and configuration of the Langchain task with guided assistance.
Configuration Modes
Default: Simple Chat
By default, the Langchain task provides straightforward LLM chat functionality. Just configure your LLM provider and start chatting.
Optional: Agent Mode with Tools
To give your LLM access to tools (calculator, web search, weather, etc.), set enableBuiltInTools: true in your configuration.
The task automatically switches to agent mode when tools are enabled.
Note: Custom HTTP call tools (via the tools parameter) are also supported. You can provide a list of EDDI HTTP call URIs to give the agent access to your own APIs.
Simple Chat Configuration
This is the standard way to use the Langchain task - just connect to an LLM and start chatting.
Basic Example
Configuration Parameters
Core Parameters
apiKey
string
API key for the LLM provider
Required
modelName
string
Model identifier (e.g., "gpt-4o", "Claude")
Provider-specific
systemMessage
string
System message for LLM context
""
prompt
string
Override user input (if not set, uses actual input)
""
Context Control
logSizeLimit
int
Conversation history limit
-1 (unlimited)
includeFirstAgentMessage
boolean
Include first agent message in context
true
Output Control
convertToObject
boolean
Parse response as JSON. Enables three-layer enforcement: system prompt reinforcement, native API JSON mode (see the provider matrix), and pre-parse validation
false
responseSchema
string
JSON schema for structured output. When set with convertToObject=true, the exact schema is injected into the system prompt so the LLM knows the expected format
""
addToOutput
boolean
Add response to conversation output
false
Logging
logRequests
boolean
Log API requests (sync and streaming)
false
logResponses
boolean
Log API responses (sync and streaming)
false
API Configuration
temperature
string
Model temperature (0-1)
Provider-specific
These three settings are part of a model's identity. Two tasks that differ only in
timeout,logRequestsorlogResponsesget two separate cached model instances, so a task always runs with the settings it declares regardless of which task was constructed first.Logging is EDDI's, not the provider's.
logRequests/logResponsesare honoured by EDDI's own model decorators, which truncate the logged request to 200 and the logged response to 500 characters. They are deliberately not forwarded to the provider builders: langchain4j's client-level logging writes whole request and response bodies at INFO with no truncation, so switching it on would put full prompts, full conversation history and full model output into the application log. (logRequestsAndResponses, which only the Azure OpenAI and Gemini builders accept, is a provider-level escape hatch and is still forwarded — use it only where that exposure is acceptable.)An unusable
timeoutis ignored, not fatal. The value is normalised once before it reaches a provider builder: it is trimmed, and dropped entirely when it is blank, non-numeric ("30s") or non-positive ("0", historically "no timeout"), with a WARN naming the model type. Provider builders parse the value with an unguardedLong.parseLong, so without this a stored config carrying one of those values would fail on every turn." 5000 "and"5000"are the same timeout and share one cached model.
Output Token Limits
The maxTokens parameter controls the maximum number of output tokens the LLM can generate per response. This is a ceiling, not a target — the model generates only what it needs and stops. Setting it higher does not increase cost unless the model actually produces more tokens; the timeout parameter is the real cost safety net.
[!WARNING] Anthropic + Extended Thinking: Models with extended thinking (e.g.
claude-sonnet-5,claude-sonnet-4) count thinking tokens towardmaxTokens. If the limit is too low, thinking can consume the entire budget, leaving zero tokens for the actual response — resulting in empty/null output. This is a silent failure: the API returns successfully, token usage shows consumption, buttext()isnull.
Provider Limits and EDDI Defaults
Anthropic
maxTokens
8,192 (standard) / 128,000 (with extended thinking)
16,384
Required by API. Set higher for thinking models
Gemini
maxOutputTokens
65,536
Provider SDK default
Use maxOutputTokens (not maxTokens)
OpenAI
maxTokens
4,096–16,384 (model-dependent)
Provider SDK default
Azure OpenAI
maxTokens
Same as OpenAI
Provider SDK default
Bedrock
maxTokens
Model-dependent
Provider SDK default
Mistral
maxTokens
32,768
Provider SDK default
Oracle GenAI
maxTokens
Model-dependent
Provider SDK default
Recommended Settings
For most conversational use cases:
For complex analysis, multi-step reasoning, or models with extended thinking:
For maximum output (e.g. long-form document generation):
Timeouts and Streaming
Two settings bound an LLM call, and they are deliberately distinct:
timeout (parameters)
model parameter
ms
The provider call. On a non-streaming task it bounds the whole request. On a streaming task it is the provider HTTP client's request/read timeout — for the JDK client, the time until the provider's first response, so it catches a provider that never answers without truncating one that answers slowly.
streamingTimeoutSeconds (task field)
task-level, sibling of parameters
s
The overall wall-clock backstop for the whole stream, for providers whose native timeout does not fire (or does not exist). Streaming only.
How the backstop is resolved:
An explicit positive
streamingTimeoutSecondsalways wins.Otherwise the backstop is 120s, raised (never lowered) to cover a longer explicitly configured
timeout. Sotimeout: "300000"with nostreamingTimeoutSecondsyields a 300s backstop rather than being cut short at 120s; anytimeoutat or below 120s leaves the 120s default untouched.Otherwise 120s.
Both stored shapes therefore keep working: a config that sets only streamingTimeoutSeconds behaves exactly as before, and a config that sets only timeout is now honoured on the streaming path instead of being discarded.
timeoutis read from the task's stored parameters when deriving the backstop. A Qute-templated value (e.g."{vars.llm-timeout}") cannot be resolved at that point and simply leaves the 120s default in place — it never produces a shorter bound.
Provider-Specific Examples
OpenAI
Anthropic Claude
Important: Anthropic doesn't allow the first message to be from the agent, so
includeFirstAgentMessageshould be set tofalse.maxTokens: Anthropic requires
max_tokensin every request. If omitted, EDDI defaults to 16384. For models with extended thinking (e.g.claude-sonnet-5), thinking tokens count toward this budget — set it higher (e.g."32768"or"65536") for complex analysis tasks.
Google Gemini (Vertex AI)
Ollama (Local Models)
Hugging Face
Jlama (Local Java Inference)
Note: Jlama runs models locally in Java without requiring external services like Ollama.
Mistral AI
Azure OpenAI
Note: Azure OpenAI uses deploymentName (not modelName) and requires an endpoint URL for your Azure instance.
Amazon Bedrock
Note: Bedrock uses modelId (not modelName) and does not require an apiKey. Authentication is via the AWS SDK default credential chain (environment variables, IAM roles, ~/.aws/credentials).
Oracle GenAI
Note: Oracle GenAI does not require an apiKey. Authentication is via OCI SDK (~/.oci/config). The configProfile parameter selects which OCI profile to use (defaults to "DEFAULT").
DeepSeek / Cohere (via OpenAI-Compatible Endpoints)
Note: Any OpenAI-compatible provider (DeepSeek, Cohere, etc.) can be used by setting the baseUrl parameter on the openai type. No additional dependencies are required.
Agent Mode (Enhanced Features)
AI Agent with Built-in Tools
Agent Mode Parameters
Tool Configuration
enableBuiltInTools
boolean
Enable built-in tools
false
builtInToolsWhitelist
string[]
Specific tools to enable
(all if not specified)
tools
string[]
Custom HTTP call tool URIs to enable
(none)
Context Control
conversationHistoryLimit
int
Max conversation turns in context
10
maxToolContextTokens
int
Aggregate token ceiling on the in-turn tool-call context (tool requests + tool results across all loop iterations). The oldest complete tool exchange is evicted when exceeded. -1/0 disables. See In-Turn Tool Context Budget.
60000
Cost & Performance
maxBudgetPerConversation
number
Ceiling on accumulated tool cost per conversation, in USD. Records cost; only refuses calls when enforceBudget is on
(unlimited)
enforceBudget
boolean
Refuse tool calls once maxBudgetPerConversation is passed. Opt-in — a ceiling without it is report-only, and is named in a startup WARN
false (eddi.tools.budget.enforce-by-default)
toolPricing
map
Per-call tool prices in USD. Keyed on the built-in slug ({"websearch": 0.005}) or on a single dispatch name ({"searchNews": 0.01}), which takes precedence — so one operation can be priced apart from its siblings
(built-in defaults)
enableToolCaching
boolean
Cache tool results to reduce API calls
true
toolCacheScopes
map
Per-tool cache partition: user/conversation/global
(all user)
defaultToolCacheScope
string
Cache partition for tools without an override
user
enableRateLimiting
boolean
Limit tool/LLM usage rate
true
Behavioral Safety (Counterweight & Identity Masking)
EDDI provides two per-task safety mechanisms that are injected into the system prompt before sending it to the LLM. Both must be explicitly enabled with "enabled": true — they are off by default.
Behavioral Counterweight
Counterweights append behavioral safety instructions to the system prompt. Three preset levels are available:
normal
No-op — no safety instructions added (default)
cautious
Adds guidelines for careful responses, hedging on uncertain topics, and suggesting professional consultation
strict
Adds stronger instructions: refuse harmful content, flag uncertainty, always suggest human oversight
Auto-downgrade: When an agent runs via the scheduled channel (e.g., ScheduleFireExecutor), strict is automatically downgraded to cautious to prevent overly rigid responses in automated pipelines.
Configuration:
counterweight.enabled
boolean
Enable counterweight injection
false
counterweight.level
string
normal, cautious, or strict
normal
counterweight.placement
string
suffix (after system prompt) or prefix (before)
suffix
counterweight.customInstructions
string[]
Custom instruction list that overrides the preset entirely
(none)
Note: Both
enabled: trueand alevelother thannormalare required for counterweight to have any effect.
Customizing presets: Counterweight preset text is resolved from Prompt Snippets (keys counterweight-cautious and counterweight-strict). If no snippet exists, built-in defaults are used. This allows admins to customize safety language via the REST API without redeployment.
Identity Masking
Identity masking prepends identity concealment rules to the system prompt. This prevents the LLM from revealing its model name, provider, or underlying architecture when asked.
Configuration:
identityMasking.enabled
boolean
Enable identity masking
false
identityMasking.rules
string[]
Identity rules prepended to system prompt
[] (empty)
Note: Both
enabled: trueand at least one rule are required. Ifrulesis empty, masking is skipped even when enabled.
Execution order: Identity masking is applied first, then counterweight. Both modify the system prompt before it is sent to the LLM.
Built-in Tools
When enableBuiltInTools: true, you can use these tools:
Calculator
Safe math expressions (sandboxed parser)
calculator
Date/Time
Get current date, time, timezone info
datetime
Web Search
Search the web (includes Wikipedia & News)
websearch
Data Formatter
Format JSON, CSV, XML data
dataformatter
Web Scraper
Extract content from web pages (SSRF-protected)
webscraper
Text Summarizer
Summarize long text
textsummarizer
PDF Reader
Extract text from PDF URLs (SSRF-protected)
pdfreader
Weather
Get weather information
weather
Tool Configuration (Server-Side)
Some tools require API keys or external configuration to function. These are configured via Environment Variables or application.properties on the EDDI server.
Web Search Tool
By default, the tool uses DuckDuckGo (HTML scraping), which requires no configuration.
To use Google Custom Search (more reliable/structured), configure these properties:
Docker Environment Variables:
EDDI_TOOLS_WEBSEARCH_PROVIDER=googleEDDI_TOOLS_WEBSEARCH_GOOGLE_API_KEY=...EDDI_TOOLS_WEBSEARCH_GOOGLE_CX=...
Weather Tool
The weather tool uses OpenWeatherMap. You must provide an API key:
Docker Environment Variables:
EDDI_TOOLS_WEATHER_OPENWEATHERMAP_API_KEY=...
Example: Selective Tool Enablement
This enables only calculator, datetime, and websearch tools.
Example: Enable All Tools
Omitting builtInToolsWhitelist enables all available built-in tools.
Custom HTTP Tools
In addition to built-in tools, you can give your agent access to any configured EDDI HTTP call. This allows the agent to interact with your own APIs or third-party services.
Configuration
To enable custom tools, add the tools property to your task configuration with a list of HTTP call URIs.
How it Works
Configuration: You provide the URIs of the HTTP calls you want the agent to use.
Discovery: The agent is automatically informed about these tools and how to use them.
Execution: When the agent decides to use a tool, it calls the
executeHttpCallfunction with the tool's URI and necessary arguments.Security: The agent can only execute the HTTP calls explicitly listed in the
toolsarray. It cannot make arbitrary HTTP requests to the internet.
Extended Configuration Options
The Langchain task supports advanced pre-request and post-response processing for fine-tuned control over task behavior.
Complete Configuration Example
Configuration Parameters Explained
Pre-Request Configuration
preRequest.propertyInstructions: Defines properties to be set before making the request to the LLM API
name: The property name
valueString: The value to be assigned (supports templating)
scope: The scope of the property (
step,conversation,longTerm)
Post-Response Configuration
postResponse.propertyInstructions: Defines properties to be set based on the LLM response
name: The property name
valueString: The value to be assigned (supports templating)
scope: The scope of the property
postResponse.outputBuildInstructions: Configures how the response should be transformed into output (alternative to
addToOutput)pathToTargetArray: The path to the array in the response
iterationObjectName: The name of the object for iterating
outputType: The type of output to generate
outputValue: The value to be used for output (supports templating)
postResponse.qrBuildInstructions: Configures quick replies based on the response
pathToTargetArray: The path to the quick replies array
iterationObjectName: The name of the object for iterating
quickReplyValue: The value for the quick reply (supports templating)
quickReplyExpressions: The expressions for the quick reply
Response Metadata
responseObjectName: Name for storing the full response object in memory
responseMetadataObjectName: Name for storing response metadata (token usage, finish reason) in memory
Conversation Window Management
EDDI provides two modes for controlling how much conversation history is sent to the LLM:
Step-Count Window (Default)
The default mode uses conversationHistoryLimit (or logSizeLimit parameter) to include the last N conversation steps. This is simple and backward compatible.
Token-Aware Window with Anchored Opening
For production workloads where token costs matter, EDDI supports token-budget windowing that also anchors the first N steps to preserve the opening context.
Configuration
maxContextTokens
int
Maximum token budget for conversation history (excluding system prompt). -1 = use step count.
-1
anchorFirstSteps
int
Number of opening conversation steps to always include regardless of window position.
2
Example
This agent:
Uses at most 4000 tokens of conversation history (excluding the system prompt)
Always includes the first 2 conversation steps (the user's initial requirements)
Fills the remaining budget with the most recent messages
Inserts a gap marker between anchored and recent messages when turns are omitted
Token Counting
OpenAI / Azure OpenAI: Uses tiktoken-based tokenizer (accurate, model-specific)
All other providers: Uses an approximate tokenizer (characters ÷ 4)
When maxContextTokens is -1 (default), the existing conversationHistoryLimit step-count behavior applies. Full backward compatibility is guaranteed.
In-Turn Tool Context Budget
maxContextTokens and conversationHistoryLimit bound the conversation history — the turns already on the record. They do not bound the messages a single tool-using turn accumulates while it runs. Inside one turn the agent loop appends the model's tool-call request and every tool result, iteration after iteration, up to maxToolIterations. Verbose tools (web scrapes, full PDF dumps, raw API bodies) can push that in-turn context past the model's context window and hard-fail the whole turn with a provider 400 — mid-loop, after the tool side effects have already happened. Per-tool toolResponseLimits help only when they are configured; they have no default, so an ordinary agent runs unbounded.
maxToolContextTokens puts an aggregate ceiling on that in-turn tool traffic:
It counts only tool traffic — every
AiMessagethat carries tool-call requests plus itsToolExecutionResultMessages, summed across all iterations of this turn (and across a HITL pause, which replays the same transcript). System, user and assistant-prose messages are never counted or touched here — that is whatmaxContextTokensgoverns.When the ceiling is exceeded, the oldest complete tool exchange — a requesting
AiMessagetogether with all of its results — is dropped before the next model call, repeatedly, until the traffic fits. Requests and their results are always evicted together: dropping one without the other leaves a danglingtool_call_idthat itself provokes the400the budget exists to prevent.The most recent exchange is never evicted. If it alone exceeds the ceiling the request is sent unchanged (the model asked for those results and must see them) and the overrun is logged — reach for
toolResponseLimitsor a lowermaxToolIterationsin that case.The same token estimator used for conversation windowing is reused, so a budget expressed in tokens means the same thing in both halves of the request (tiktoken for OpenAI/Azure, characters ÷ 4 elsewhere).
Default: 60000. High enough that no ordinary tool-using turn is ever touched — the guard is byte-for-byte inert below the ceiling, so agents that work today are unaffected — and low enough to keep a runaway loop inside a 128k context window once the system prompt, the conversation history and the model's own completion are added. Set -1 (or 0) to disable the guard and restore the pre-6.1 unbounded behaviour.
Observability. Eviction is never silent: it emits a tool_context_evicted entry in the execution trace (with token counts before/after, exchanges and messages dropped, and whether the result is within budget), increments the eddi.llm.tool_context.evictions counter (tagged outcome=within_budget|still_over_budget), and logs a WARN (llm.tool_context.evicted) carrying the conversation id and the remediation hint. Because eviction removes tool results the model can no longer see, treat a steady stream of these as a signal to lower maxToolIterations, set toolResponseLimits, or raise maxToolContextTokens.
API Endpoints
The Langchain task configurations can be managed via REST API endpoints.
Endpoints Overview
Read JSON Schema
Endpoint:
GET /langchainstore/langchains/jsonSchemaDescription: Retrieves the JSON schema for validating Langchain configurations
List Langchain Descriptors
Endpoint:
GET /langchainstore/langchains/descriptorsDescription: Returns a list of all Langchain configurations with optional filters
Read Langchain Configuration
Endpoint:
GET /langchainstore/langchains/{id}Description: Fetches a specific Langchain configuration by its ID
Update Langchain Configuration
Endpoint:
PUT /langchainstore/langchains/{id}Description: Updates an existing Langchain configuration
Create Langchain Configuration
Endpoint:
POST /langchainstore/langchainsDescription: Creates a new Langchain configuration
Duplicate Langchain Configuration
Endpoint:
POST /langchainstore/langchains/{id}Description: Duplicates an existing Langchain configuration
Delete Langchain Configuration
Endpoint:
DELETE /langchainstore/langchains/{id}Description: Deletes a specific Langchain configuration
Tool Execution Pipeline
All tool invocations—both built-in tools and custom HTTP call tools—are routed through a unified Tool Execution Service that applies enterprise-grade controls:
Controls
Rate Limiting
Token-bucket per tool, configurable limits
enableRateLimiting, defaultRateLimit, toolRateLimits
Smart Caching
Deduplicates identical tool calls, partitioned per identity
enableToolCaching, toolCacheScopes, defaultToolCacheScope
Cost Tracking
Per-conversation tool-cost accounting, with an opt-in ceiling and automatic stale-data eviction
enableCostTracking, toolPricing, maxBudgetPerConversation, enforceBudget
Tool names: dispatch name vs. configuration slug
A built-in tool has two names, and knowing which one a setting expects is the difference between a rule that binds and one that is silently ignored:
the slug — the token you write in
builtInToolsWhitelist(websearch,calculator,datetime, …). This is a property of the tool.the dispatch name — the
@Toolmethod the model actually calls (searchWeb,searchNews,searchWikipediaall belong towebsearch). This is a property of the individual operation.
builtInToolsWhitelist
slug only
toolRateLimits
slug or dispatch name — dispatch name wins
toolPricing
slug or dispatch name — dispatch name wins
toolCacheScopes
slug or dispatch name — dispatch name wins
toolApprovals
dispatch name, optionally source:name-qualified
cache TTL, default price
slug (resolved automatically)
eddi.tool.* metric tool tag
dispatch name
Rate-limit buckets are per dispatch name.
{"websearch": 30}sets the limit for the whole tool but givessearchWeb,searchNewsandsearchWikipedia30 calls/minute each, not 30 between them. Pin a single operation by using its dispatch name:{"searchNews": 5}.
Budgets
maxBudgetPerConversation bounds tool cost only — the accumulated per-call prices of the tools a conversation invokes. LLM token spend is a separate, run-scoped concern governed by the model cascade's maxCostPerRun; the two are not added together.
Enforcement is opt-in: a configured ceiling records cost but refuses nothing until you add enforceBudget: true. Built-in tools priced at $0.00 until the canonical-slug fix in this release, so enforcing automatically would make those ceilings bind for the first time and start aborting tool calls mid-conversation on upgrade.
That choice has a real cost, which is why the engine warns rather than staying quiet: http, MCP, A2A and dynamic tools dispatch under their configured name, so a tool called websearch was priced and refused before enforceBudget existed. If you relied on such a ceiling, add the flag — every task carrying a ceiling without it is named once in a startup WARN. Cost is tracked and reported (GET /llm/toolhistory/costs, eddi.tool.costs) either way. The deployment-wide default comes from eddi.tools.budget.enforce-by-default (default false).
The check runs before each call and uses <=, so the call that crosses the ceiling still completes and the next one is refused with Error: Budget exceeded for conversation <id>.
Default per-call prices: webscraper $0.002, websearch $0.001, pdfreader $0.001, weather $0.0005; calculator, datetime, dataformatter and textsummarizer are free. Anything not in that table — http, mcp, a2a, dynamic and the remaining built-ins — costs $0.00 until you price it with toolPricing. Negative toolPricing values are clamped to 0.0.
Tool cache scoping
Cached tool results are partitioned by identity. The cache key is scopeTag|toolName:arguments, and the scope tag is resolved per tool call as toolCacheScopes[<dispatch name>] → toolCacheScopes[<slug>] → defaultToolCacheScope → user:
user
u:<32 hex chars of SHA-256(userId)>
only for the same authenticated user (default)
conversation
c:<conversationId>
only inside the conversation that produced it
global
g
by everyone — opt-in only
Choose global only for tools whose result depends purely on their arguments and never on who is asking (pure computation, public reference data). It is the one setting that permits cross-user reuse.
When user scope applies but there is no user id, the entry falls back to the narrower conversation partition. When neither identity is available the cache is bypassed entirely for that call — nothing is read and nothing is stored, and the eddi.tool.cache.bypassed counter is incremented.
An unrecognized token never fails the agent load, and it never widens a tool's audience either. A toolCacheScopes entry whose value does not parse ("usr", "", null) resolves to user — not to defaultToolCacheScope, which could be global — and is logged at WARN naming the tool and the bad token. An unrecognized defaultToolCacheScope likewise resolves to user.
Per-tool TTLs are enforced per entry: a cached result is removed once its own TTL has elapsed since it was written, independently of the other entries in the cache. The TTL is resolved from the dispatch name first and the slug second, so searchNews gets the 10-minute news TTL while its searchWeb sibling inherits websearch's 30 minutes. GET /llm/tools/cache/ttl/{toolName} reports the TTL that will be applied. Size eviction (10 000 entries) is the secondary bound.
Configuration Example
Security Hardening
Tools that accept URLs from LLM-generated arguments are protected against Server-Side Request Forgery (SSRF):
Only
httpandhttpsschemes are allowedPrivate/internal IP ranges are blocked (loopback, site-local, link-local)
Cloud metadata endpoints are blocked (
169.254.169.254,metadata.google.internal)Internal hostnames (
.local,.internal,localhost) are rejected
The Calculator tool uses a sandboxed recursive-descent math parser (SafeMathParser) instead of a script engine, eliminating any possibility of code injection.
See the Security documentation for full details.
Monitoring & Observability
EDDI provides built-in metrics for monitoring agent performance:
Tool execution success/failure rates
Response latency (P50, P95, P99)
Cache hit rates
Cost tracking
Rate limit violations
See the Metrics Documentation for details on configuring Prometheus/Grafana monitoring.
Complete Example: Multi-Capability Agent
This agent can:
✅ Perform calculations
✅ Get date/time info
✅ Search the web
✅ Check weather
✅ Maintain 10 turns of conversation history
Integration with Behavior Rules
To trigger the Langchain task, configure Behavior Rules to emit the appropriate action:
Then reference this action in your Langchain task:
Structured Output (JSON Mode)
When you need the LLM to return a specific JSON structure (e.g., for property extraction, API response formatting, or quick reply generation), use the convertToObject parameter with an optional responseSchema.
Three-Layer Enforcement
EDDI uses three complementary mechanisms to ensure reliable JSON output:
1. System Prompt
Appends ## RESPONSE FORMAT (MANDATORY) section with schema to every request
All providers
2. Native API
Sets ResponseFormatType.JSON on the outgoing ChatRequest
See the matrix below
3. Validation
Pre-parse startsWith("{") check before deserialization
All providers
If a provider doesn't support native JSON mode (e.g. Anthropic), EDDI gracefully falls back to prompt-only enforcement.
Native JSON mode — provider matrix
Layer 2 is applied per request, never baked into the model instance, and it is applied in all three execution modes: no-tools (legacy), agent mode (tool-calling) and streaming — including every step of a multi-model cascade, which is evaluated against that step's own provider.
openai
✅
✅
azure-openai
✅
✅
mistral
✅
✅
gemini, gemini-vertex
✅
❌ — the Gemini API rejects responseMimeType: application/json together with tools
anthropic, bedrock
❌ — both reject a JSON format without a schema
❌
ollama, jlama, huggingface, oracle-genai
❌ (not verified — opt in with jsonResponseFormat: "on")
❌
Overriding the matrix per task
Set jsonResponseFormat on the LLM task (not in parameters):
auto (default)
Use the matrix above, including the tools-aware distinction
on
Always send the JSON format when convertToObject=true, tools included. The escape hatch for a provider or OpenAI-compatible gateway the matrix does not know yet — it also bypasses the Gemini guard, so only use it where you have verified the provider accepts the combination
off
Never send it; enforcement stays prompt-only
Do not set a
responseFormatmodel parameter. It is only read by the OpenAI builder and it bakes JSON mode into a cached model that is then reused for tool-calling and streaming requests — the cause of the historical Gemini400 Function calling with a response mime type: 'application/json' is unsupported.convertToObjectalone is enough.
Basic JSON Mode
With Response Schema
For maximum reliability, specify the exact JSON structure you expect:
The schema is injected into the system prompt as a JSON code block so the LLM sees the exact expected format.
Using with Output Configuration
When convertToObject=true, the LLM's JSON response is stored in conversation memory as a parsed object. You can then reference its fields in the Output Configuration:
Debugging
When convertToObject=true, the raw LLM response is always persisted in conversation memory (key: langchain:data) even if JSON parsing fails. This ensures you can inspect what the LLM actually returned via the conversation log.
Tips
Streaming: Not recommended with JSON mode — the UI would show raw JSON building up. It does work (the streamed request carries the format for supported providers), but pair it with
addToOutput: "false"and apostResponseProvider compatibility: see the provider matrix above. Unsupported providers rely on prompt-based enforcement
Schema specificity: The more specific your
responseSchema, the more reliable the output. Use type hints ("string","number","boolean") and descriptions
Common Issues and Troubleshooting
API Key Issues
Problem: "Invalid API key" errors
Solution: Ensure API keys are valid and have not expired. Renew them before expiry.
Model Misconfiguration
Problem: "Model not found" errors
Solution: Verify model names match those supported by the provider (e.g., "gpt-4o" for OpenAI, not "gpt4")
Timeout Issues
Problem: Requests timing out
Solution: Increase the
timeoutparameter value (in milliseconds). Default is often 15000 (15 seconds).Problem: A streaming turn is cut off after ~120s even though
timeoutis largerSolution: This was the behaviour before the
timeout/streamingTimeoutSecondsunification; the backstop now follows a longertimeoutautomatically. SetstreamingTimeoutSecondsexplicitly if you need a bound that differs from the derived one — see Timeouts and Streaming.
Anthropic First Message Error
Problem: Anthropic API rejects conversations starting with agent message
Solution: Set
includeFirstAgentMessage: "false"for Anthropic tasks
Tool Not Working
Problem: Agent not using expected tools
Solution:
Verify
enableBuiltInTools: trueis setCheck
builtInToolsWhitelistincludes the desired toolEnsure the model supports tool calling (e.g., gpt-4o, not gpt-3.5-turbo)
Response Not Added to Output
Problem: LLM response not visible to user
Solution: Set
addToOutput: "true"in parameters, or configurepostResponse.outputBuildInstructions
Tool Execution Context
Understanding how tools execute is critical for designing new built-in tools and avoiding common pitfalls.
Execution Path
All LLM tools execute inside a conversation pipeline. The full execution path is:
Implicit Context
IConversationMemory is always available when tools execute. Tools that need conversation state (e.g., userId, agentId, groupIds) receive it via constructor injection from AgentOrchestrator, which has the memory object at tool-list build time.
This means:
No ThreadLocal or request-scoped beans needed
No
userIdparameter on LLM tools — the conversation always knows who the user isOnly external interfaces (MCP, REST) that operate outside a conversation need explicit user identification
LLM Tools vs MCP Tools
Execution context
Inside conversation pipeline
Outside conversation
User identification
Implicit from IConversationMemory
Explicit userId parameter
Registration
builtInToolsWhitelist in langchain config
McpMemoryTools.java
Audience
The LLM agent itself
External AI agents or admin tooling
See Also
Behavior Rules - Triggering LLM tasks conditionally
HTTP Calls - Creating custom HTTP call tools for agents
Security - SSRF protection, sandboxed evaluation, tool hardening
Output Configuration - Formatting agent responses
Conversation Memory - Understanding conversation state
Metrics - Monitoring LLM performance
Summary
The LLM Lifecycle Task provides a flexible, unified interface for integrating LLMs into EDDI agents:
✅ Simple by Default - Start with basic chat, add tools when needed
✅ 12 Provider Support - OpenAI, Anthropic, Google, Mistral, Azure, Bedrock, Oracle, Ollama, Hugging Face, Jlama + OpenAI-compatible (DeepSeek, Cohere)
✅ Built-in Tools - 8 tools available when you enable agent mode
✅ Tool Execution Pipeline - Rate limiting, caching, cost tracking for every tool call
✅ Security Hardened - SSRF protection, sandboxed math evaluation, input validation
✅ Fine-Grained Control - Pre/post processing, context management, templating
✅ Orchestration Layer - Conditional invocation, hybrid workflows, state persistence
✅ Easy Configuration - Use Agent Father for guided setup
Whether you need simple chat or advanced agent capabilities, the Langchain task provides the foundation for intelligent conversational experiences in EDDI.
Last updated
Was this helpful?