Repository navigation
EDDI 6.6.0 is about running EDDI at scale and under failure, and about control over what agents do.
- 📈 Scale and overload. Turns run on virtual threads behind an in-flight limit, EDDI scales out on NATS JetStream, database round trips per turn dropped from 16.7 to about 6.5, and overload is refused early with
503instead of queueing without bound. - 🛟 LLM turns that survive failure. Failures are classified and retried by one owner, bad output is re-asked, a failing model is circuit-broken, and callers get structured errors and
Idempotency-Keyretries. - 🎚️ Every provider parameter. All 19 LLM integrations now read every parameter their API accepts (
topP,seed,stopSequences, reasoning controls and vendor fields). A model-aware catalog warns about settings a model rejects or ignores, and the Manager has a settings panel. A newopenai-compatibletype covers vLLM, llama-server, TGI and LiteLLM. - 📚 RAG you can see and trust. Ingestion shows live progress, run details and schedule status in the Manager, a knowledge-base inspector tests retrieval, and every knowledge base now has an isolated store.
- 🚧 Governance. Input and output guardrails (including a classifier backed by your own safety model), a per-conversation cost ceiling, an enforced tenant monthly budget, and agent test suites ("golden conversations").
- 🔌 Integration. A signed inbound webhook channel (CloudEvents), A2A 1.0, and W3C trace propagation on outbound calls.
- 🔒 Hardening. Fixes for secret handling, authorization gaps, outbound requests and deployment defaults. Many apply to code that shipped in 6.5.0 or earlier, so upgrading is recommended regardless of the new features.
Please read the Breaking Changes before upgrading.
🚀 What's New
📈 Scale & Overload
- 🧵 Virtual-thread turns.
eddi.conversation.max-in-flight-turnsis now derived from the heap by default. Past the limit a turn is refused with503 capacity_exceededandRetry-After, before any database read. One conversation may queue at most 20 turns, and a MongoDB pool wait is capped at 10 s instead of 120 s. - ⏱️ The turn timeout holds under load.
agentTimeoutInSecondscounts from the request's arrival. A caller whose time ran out gets408, and a turn still queued for them is dropped without running (input kept,Idempotency-Keyreleased)./q/metricsis served on its own threads, so graphs no longer go blank during a burst. - 🗄️ Fewer database round trips per turn: 16.7 → about 6.5.
- 🌐 Cluster mode.
eddi.messaging.type=natsis read at runtime from the one image: any number of replicas behind a round-robin load balancer, one database, one NATS cluster. Leases with fencing, dead letters, and one turn per idempotency key across nodes. The Manager gets a cluster console with health, leases, dead letters and safe recovery actions.in-memorystays the default. - 📏 Load-test suite (
scripts/loadtest): throughput, streaming time to first token, cluster scaling, group discussions, and a CI gate on database operations per turn.
🛟 Resilient LLM Turns
- Failure classification: a daily quota is no longer retried like a per-minute limit, the provider's retry delay is honoured, and langchain4j's own retries no longer stack under EDDI's.
- Recovery policies:
responseValidationcan re-ask the same model before escalating (onInvalidJson,onSchemaMismatch,onContextTooLong).responseSchemaandnonBlankFieldscatch valid JSON of the wrong shape. circuitBreaker(opt-in) skips a model that cannot answer at all.- One turn deadline (
turnDeadlineMs,X-EDDI-Turn-Deadline-Ms) across retries, cascade steps and HTTP calls. - Tool repeat guard refuses identical failing tool calls (on by default, see Breaking Changes).
- Structured errors and idempotent turns: a failed turn returns
error.code,retryableandRetry-After; resending with the sameIdempotency-Keyreturns the finished answer instead of409 IN_PROGRESS.
🚧 Governance & Testing
- Guardrails.
inputGuardrailsandoutputGuardrailson an LLM task screen for prompt-injection phrasing, PII, regex, length and JSON shape withblock,warn,redactorreprompt, on every path including streaming and HITL resume. Aclassifierguardrail sends the text to a safety model you configure (Granite Guardian, ShieldGemma, any registered provider or OpenAI-compatible endpoint). Only a positive match ofsafeLabelcounts as safe, andfailModedefaults toclosed. - Cost.
maxCostPerConversationUsdon the agent bounds one conversation, group-member turns included. The tenantmaxMonthlyCostUsdbudget was stored but never metered; settled turns and Dream runs are now charged and the model-call gate trips when it is spent. - Agent test suites. An
AgentTestSuiteconfig holds scripted cases with per-turn expectations (actionsContain,properties,outputContains,toolCalled,maxCostUsd) and tool mocks that fail closed. Runs go against thetestenvironment, are capped by a per-run dollar ceiling (default $1) and never touch long-term user memory. Available over REST, MCP and in the Manager.
🔌 Integration
- Signed webhook channel.
channelType: "webhook"exposesPOST /integrations/webhook/{integrationId}. The HMAC over the raw body is checked fail-closed (eddi-v1,githuborgeneric-hmac). CloudEvents and plain JSON arrive as the context valueevent(data, never a template) and route by event type to an agent or group. - A2A 1.0. Agent Cards and tasks follow the spec (1.0 and 0.3 served from one endpoint). Task states are honest: a failing LLM or a HITL pause is no longer reported as
completed. Tasks survive a restart. - Observability. W3C trace context propagates on outbound calls, and every tool call gets an
execute_toolspan. - Platform Operator. It can look up the running version, edit configs that hold vault references, and explain
503,408and node sizing.
🔄 Promote Without Ending Conversations
A conversation follows newer agent versions only within its compatibility generation, and imports and syncs used to break it. Now:
POST /backup/importand/backup/import/sync[/batch]takecompatible(defaultfalse, so nothing changes unless you ask). Previews show how many open conversations would follow.POST /administration/{environment}/upgradeconversations/{agentId}(MCP:upgrade_conversations) moves already-pinned conversations onto the current version. It defaults to a dry run.
⚠️ Breaking Changes & Upgrade Notes
| Change | Impact |
|---|---|
🔑 Secret creates need allowedHosts |
With eddi.vault.grant-enforcement=enforce (the default), creating a secret without allowedHosts returns 400. ["*"] opts out explicitly. Rotations are unaffected. |
| 🗄️ MongoDB user | EDDI connects as eddi_app instead of root. Compose and Helm create the user on every start, so existing volumes migrate without a manual step. Kustomize users with their own mongodb-secrets need the patch in docs/upgrading-from-6.5.md. |
| 🪪 Keycloak default password | docker-compose.auth.yml refuses to start Keycloak off loopback while the bootstrap password is unset or admin. |
| 🚦 Overload answers | Clients can now receive 503 capacity_exceeded (limit reached, queue full, database pool wait) and 408 (their time ran out) and should honour Retry-After. |
| 📦 Resource defaults | The image uses 75 % of the memory limit as heap, G1, and exits on out-of-memory. Helm and Kustomize request 1 CPU and 3 GiB (production overlay 2 CPU and 4 GiB). Check that your nodes can schedule it. |
| 🔁 Tool repeat guard on by default | Disable per agent with "toolRepeatGuard": {"enabled": false}. |
| 🌐 SSRF switch covers more | With eddi.security.ssrf-protection.enabled=true, LLM, embedding, vector-store and OpenAPI-discovery targets are checked too. Self-hosted model servers on private addresses should use the openai-compatible type or leave the switch off. |
| 🔒 Credentials hidden from editors | Non-admins no longer read plaintext credentials in any config store. Resetting a tenant's vault requires confirm=true. |
| 🧩 Hugging Face | Uses the langchain4j default router when baseUrl is unset. baseUrl is the service root without models/. |
| 🛰️ Cluster | Messaging is chosen by eddi.messaging.type at runtime. Any value other than in-memory or nats fails the boot. |
Take a backup before upgrading.
🔒 Security
- Secrets go only where allowed:
allowedHostsis enforced for LLM, embedding, vector-store, MCP and A2A references and editable in the Manager; no default grant on create; wider redaction of provider key shapes and Digest headers. - Authorization gaps closed in directory listings, workflow references, group
USEchecks,platform.*variables and group attachments. GDPR erasure and export now reach group discussions. - Outbound requests: one facade for SSRF policy, redirects, header stripping and body caps; unreadable hosts are refused; log lines are sanitised.
- Hostile input: the expression parser, dictionary regexes, template string operations and JSON fence stripping are bounded.
- Deployment: CI/CD, Helm, Compose and installer fixes.
SHA256SUMSis signed with cosign and the installers verify it. - MCP: remote tool schemas are checked, redirects refused, tool budgets enforced by default, and
read_audit_trailhidescompiledPromptfrom callers without VIEW on the agent.
🐛 Bug Fixes
- Malformed model JSON no longer fails a turn; fenced or prose-wrapped JSON is recovered.
- A HITL-paused turn is delivered only after the pause is persisted, and approval cards are never approvable before they describe the pause.
- 5.x migration: the properties migration runs in the background with progress logging, 5.x LLM defaults carry over, and nested conditionals convert correctly.
- An idle sweep no longer loads every open conversation; a bulk "end inactive conversations" exists.
- Alert rules are shipped and loaded, and empty or duplicate monitoring panels are fixed.
📦 Dependency Updates
langchain4j 1.20.2 → 1.22.0, quarkus-mcp-server 2.0.1 → 2.0.3, PostgreSQL JDBC 42.7.13 → 42.7.14, classgraph 4.8.196 → 4.8.199, Node (UI build) 24.21.0 → 24.22.0.
🖥️ EDDI Manager
New screens for guardrails, agent test suites, cost limits, the cluster console and ingestion; a model picker that shows the full catalog; and a consistency pass over saves, unsaved-changes guards, layout at every screen size and RTL.
📋 Full Changelog
6.5.0...6.6.0. See docs/changelog.md and docs/changelog/2026-10.md for per-change detail and design decisions.
🐳 Docker Image
docker pull labsai/eddi:6.6.0cosign verify \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity-regexp '^https://github\.com/labsai/EDDI/\.github/workflows/ci\.yml@refs/(heads/main|tags/[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?)$' \
labsai/eddi:6.6.0EDDI is distributed exclusively as a Docker image. There are no binary downloads.