Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions .github/workflows/redhat-certify.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,25 @@ on:
workflow_dispatch:
inputs:
version:
description: 'EDDI version (e.g. 6.0.2)'
description: "EDDI version (e.g. 6.1.0)"
required: true
default: '6.0.2'
default: "6.1.0"
release:
Comment thread
ginccc marked this conversation as resolved.
Resolved
description: 'Release number (e.g. 1, 2, 3)'
description: "Release number (e.g. 1, 2, 3)"
required: true
default: '1'
default: "1"
submit:
description: 'Submit results to Red Hat (true/false)'
description: "Submit results to Red Hat (true/false)"
required: true
default: 'true'
default: "true"
type: choice
options: ['true', 'false']
options: ["true", "false"]
registry:
description: 'Target registry'
description: "Target registry"
required: true
default: 'docker.io'
default: "docker.io"
type: choice
options: ['docker.io', 'quay.io']
options: ["docker.io", "quay.io"]

permissions:
contents: read
Expand All @@ -40,7 +40,7 @@ jobs:
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5
with:
distribution: temurin
java-version: '25'
java-version: "25"
cache: maven

- name: Set execute permission for mvnw
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

Built with **Java 25** and **Quarkus**. Ships as a **Red Hat-certified Docker image**. Native support for **MCP** (Model Context Protocol), **A2A** (Agent-to-Agent), **Slack**, **OpenAPI**, and **OAuth 2.0**.

**Latest version: 6.0.2** · [Website](https://eddi.labs.ai/) · [Documentation](https://docs.labs.ai/) · License: Apache 2.0
**Latest version: 6.1.0** · [Website](https://eddi.labs.ai/) · [Documentation](https://docs.labs.ai/) · License: Apache 2.0

---

Expand Down Expand Up @@ -401,7 +401,7 @@ Building a Quarkus app that talks to EDDI? Use the **[quarkus-eddi](https://gith
<dependency>
<groupId>io.quarkiverse.eddi</groupId>
<artifactId>quarkus-eddi</artifactId>
<version>6.0.2</version>
<version>6.1.0</version>
</dependency>
```

Expand Down
122 changes: 122 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,128 @@

---

## 🔍 PR Review Fixes — Code Quality & Correctness (2026-06-03)

**Repo:** EDDI (`fix/mcp-endpoint-bugs`)
**What changed:** Addressed all findings from automated PR review bots (github-code-quality, CodeRabbit, Copilot) plus a critical exception handling bug found during manual review.

### Critical Fix: Stale Conversation Cleanup Was Dead Code
- **Root cause:** `McpConversationTools.getOrCreateManagedConversation()` caught `jakarta.ws.rs.NotFoundException`, but `RestAgentEngine.getConversationState()` actually throws `IConversationService.ConversationNotFoundException` (a plain `RuntimeException`). The JAX-RS exception was never thrown by this code path.
- **Impact:** Stale conversation mappings (pointing to deleted conversations) were never cleaned up — the exception propagated to the outer catch and returned a generic error.
- **Fix:** Changed catch to `IConversationService.ConversationNotFoundException`.
- **Test:** Updated `chatManaged_staleConversation_recreatesFresh` to throw the correct exception type.

### Other Fixes
- **Unused variable:** Removed `String result` in test (github-code-quality)
- **Field filter bypass:** `readConversation` with `returningFields=conversationOutputs` no longer strips the full payload — section-level names are now detected and preserved
- **redhat-certify.yml:** Updated default version from `6.0.2` to `6.1.0`
- **README.md:** Updated version from `6.0.2` to `6.1.0` (header badge and Maven snippet)
- **redhat-openshift.md:** Fixed YAML example indentation back to standard 2-space Kubernetes style
- **Changelog wording:** Softened "across all deployment artifacts" to "across the main deployment artifacts"

### New Tests
- `chatManaged_endedConversation_recreatesFresh` — covers `ConversationState.ENDED` → delete+recreate path
- `chatManaged_transientStateError_doesNotRecreate` — verifies transient DB errors propagate without deleting valid mappings
- `readConversationDescriptors_agentVersionFilter_matchesCorrectVersion` — agentVersion filter positive match
- `readConversationDescriptors_agentVersionFilter_filtersWrongVersion` — agentVersion filter negative match

---

## 📦 Version Bump 6.0.2 → 6.1.0 (2026-06-03)

**Repo:** EDDI (`fix/mcp-endpoint-bugs`)
**What changed:** Bumped project version from 6.0.2 to 6.1.0 across the main deployment artifacts and related documentation to reflect the scope of changes since RC2 (MCP bug fixes, dependency updates, Manager UI refresh, security hardening).

Comment thread
ginccc marked this conversation as resolved.
Resolved
### Files Updated
- `pom.xml` — Maven artifact version
- `src/main/docker/Dockerfile` — `EDDI_VERSION` build arg + Red Hat certification labels
- `helm/eddi/Chart.yaml` — `appVersion`
- `k8s/base/eddi-deployment.yaml` — `app.kubernetes.io/version` labels
- `k8s/quickstart.yaml` — `app.kubernetes.io/version` labels
- `src/main/resources/application.properties` — `systemRuntime.projectVersion`, `quarkus.smallrye-openapi.info-version`, `quarkus.container-image.additional-tags`
- `src/main/resources/initial-agents/available_agents.txt` — Agent Father ZIP filename
- `src/main/resources/initial-agents/Agent+Father-6.1.0.zip` — [NEW] updated bundled agent
- `src/main/resources/initial-agents/Agent+Father-6.0.2.zip` — [DELETED] superseded
- `.github/workflows/redhat-certify.yml` — Red Hat certification workflow version refs
- `docs/redhat-openshift.md` — documentation version refs

---

## 🐛 MCP Bug Fixes — Round 2: chat_managed + group discussion error content (2026-06-03)

**Repo:** EDDI (`fix/mcp-endpoint-bugs`)
**What changed:** Fixed 3 remaining bugs from MCP endpoint audit retest.

### chat_managed Internal Error (NEW — all calls returned "Internal error")
- **Root cause:** Missing `@Blocking` annotation on `chatManaged()`. Both `talkToAgent()` and `chatWithAgent()` had it, but `chatManaged()` did not. Since `sendMessageAndWait()` blocks on `CompletableFuture.get()`, the MCP framework's event-loop thread was blocked, causing the generic "Internal error".
- **Fix 1:** Added `@Blocking` annotation.
- **Fix 2:** Replaced `restAgentEngine.startConversationWithContext()` with direct `conversationService.startConversation()` to avoid the JAX-RS layer wrapping exceptions as HTTP responses.
- **Fix 3:** Hardened stale conversation handling — `getConversationState()` now catches `Exception` when the stored UserConversation references a deleted conversation, cleans up the stale mapping, and creates a fresh conversation.
- **Files:** `McpConversationTools.java`

### BUG-2 Follow-up: Group discussion empty content when LLM fails
- **Root cause:** `extractResponse()` correctly returns `null` when no output keys are present (pipeline metadata only), but this `null` was silently stored as the transcript `content` field — making entries appear empty.
- **Fix:** In `executeAgentTurn()`, after `extractResponse()` returns null, check the conversation state. If ERROR, set content to `"[Agent failed to produce output — conversation entered ERROR state]"`.
- **Files:** `GroupConversationService.java`

### BUG-6 Follow-up: Trigger cache invalidation (verified indirectly)
- The trigger validation in `getOrCreateManagedConversation()` was already correct from the first fix round. It was untestable because `chat_managed` itself was broken. Now that `@Blocking` is fixed, the trigger validation path is reachable.

---

## 🐛 MCP Endpoint Bug Fixes — 8 Bugs Resolved (2026-06-02)

**Repo:** EDDI (`fix/mcp-endpoint-bugs`)
**What changed:** Systematic testing of all 42 MCP endpoints revealed 8 bugs. All fixed with regression tests.

### BUG-1: `read_resource` for `langchain` returns empty `configuration: {}`
- **Root cause:** `LlmConfiguration` is the only Java record-based config class. The programmatic MP REST Client's ObjectMapper may lack `ParameterNamesModule`, causing silent deserialization failure to `LlmConfiguration(null)`, then `NON_NULL` serialization produces `{}`.
- **Fix:** Added `@JsonProperty("tasks")` to the record component.
- **Files:** `LlmConfiguration.java`

### BUG-2: Group discussion shows raw `{"actions":["send_message","unknown"]}`
- **Root cause:** `GroupConversationService.extractResponse()` fallback serialized pipeline metadata when no text output keys were found.
- **Fix:** Added metadata-only detection: if output only contains `actions`/`input`/`context` keys, return `null` instead.
- **Files:** `GroupConversationService.java`

### BUG-3: `list_conversations` returns 0 results when filtering by agentId
- **Root cause:** `RestConversationStore` used `getResource()` (conversation URI) instead of `getAgentResource()` (agent URI) for agent filtering — compared agentId against conversationId.
- **Fix:** Changed to use `getAgentResource()` for agent ID extraction.
- **Files:** `RestConversationStore.java`

### BUG-4: `read_conversation_log` NPE when logSize is null
- **Root cause:** `Integer` logSize passed directly to `int` parameter causing NPE on unboxing.
- **Fix:** Added null guard: `logSize != null ? logSize : -1`.
- **Files:** `ConversationService.java`

### BUG-5: `delete_agent_trigger` returns 200 for nonexistent intents
- **Root cause:** Both MongoDB and Postgres implementations silently accepted no-op deletes.
- **Fix:** Interface, Mongo, and Postgres stores now throw `ResourceNotFoundException` when delete count is zero. REST layer catches and returns 404.
- **Files:** `IAgentTriggerStore.java`, `AgentTriggerStore.java`, `PostgresAgentTriggerStore.java`, `RestAgentTriggerStore.java`

### BUG-6: `chat_managed` routes to stale conversation after trigger deletion
- **Root cause:** `getOrCreateManagedConversation()` reused `UserConversation` records without validating trigger existence.
- **Fix:** Validate trigger before reusing, clean up stale records if trigger is deleted.
- **Files:** `McpConversationTools.java`

### BUG-7: `delete_group`/`update_group` fail with version=0
- **Root cause:** `RestVersionInfo` didn't override `getCurrentResourceId()`, falling through to `IRestVersionInfo` default which throws.
- **Fix:** Added `getCurrentResourceId()` override that delegates to `resourceStore`.
- **Files:** `RestVersionInfo.java`

### BUG-8: `returningFields` filter in `read_conversation` has no effect
- **Root cause:** Underlying utility only handles section-level filtering, not individual field names.
- **Fix:** Added post-processing in MCP layer to filter conversationOutputs keys.
- **Files:** `McpConversationTools.java`

### Code Review Follow-up (3 additional fixes)
- **ISSUE-1:** `PostgresAgentTriggerStore.deleteAgentTrigger()` silently swallowed `SQLException` — callers thought delete succeeded on DB failure. Added `throw ResourceStoreException`.
- **ISSUE-2:** BUG-8 field filter mutated the live `ConversationOutput` map via `removeIf` — replaced with filtered copy to avoid corrupting shared/cached snapshots.
- **ISSUE-3:** BUG-2 metadata detection used a fragile hardcoded positive-list of 3 keys. Replaced with resilient absence-of-output check (`startsWith("output") || startsWith("reply")`).
- **OBS-1:** BUG-6 trigger validation used `catch (Exception)` — narrowed to `catch (ResourceNotFoundException)` so transient DB errors propagate instead of falsely deleting state.

Comment thread
ginccc marked this conversation as resolved.
Resolved
---

## 📦 Dependency Updates — June 2026 (2026-06-01)

**Repo:** EDDI (`chore/dependency-updates-june-2026`)
Expand Down
80 changes: 40 additions & 40 deletions docs/redhat-openshift.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ EDDI is built on and fully supports **Red Hat Enterprise Linux (RHEL)**. The pro

EDDI is delivered as an OCI-compliant Docker container image and runs on any platform that supports OCI containers, including:

| Platform | Support Level |
|---|---|
| **Red Hat Enterprise Linux 9** | ✅ Primary — UBI 9 base image, Red Hat-certified |
| **Red Hat OpenShift 4.12+** | ✅ Certified — listed in the [Red Hat Ecosystem Catalog](https://catalog.redhat.com/) |
| **Docker** (any Linux, macOS, Windows) | ✅ Full support — standard OCI container |
| **Kubernetes** (any distribution) | ✅ Full support — standard OCI container |
| **Podman** | ✅ Full support — OCI-compliant runtime |
| Platform | Support Level |
| -------------------------------------- | ------------------------------------------------------------------------------------- |
| **Red Hat Enterprise Linux 9** | ✅ Primary — UBI 9 base image, Red Hat-certified |
| **Red Hat OpenShift 4.12+** | ✅ Certified — listed in the [Red Hat Ecosystem Catalog](https://catalog.redhat.com/) |
| **Docker** (any Linux, macOS, Windows) | ✅ Full support — standard OCI container |
| **Kubernetes** (any distribution) | ✅ Full support — standard OCI container |
| **Podman** | ✅ Full support — OCI-compliant runtime |

> **Note**: Because EDDI ships as a standard OCI container image built on Red Hat UBI 9, it is inherently compatible with RHEL 9 and any RHEL-based platform. No host-level OS dependencies are required beyond a container runtime.

Expand All @@ -39,15 +39,15 @@ The EDDI container image is certified by Red Hat / IBM for use on OpenShift. Cer

### Certification Compliance

| Requirement | Implementation |
|---|---|
| **Base image** | `registry.access.redhat.com/ubi9/openjdk-25-runtime:1.24` (pinned by SHA256 digest) |
| **Non-root execution** | Runs as UID `185` — the default `jboss` user |
| **Licenses** | Auto-generated `/licenses` directory containing `THIRD-PARTY.txt` and downloaded license texts |
| **Required labels** | `name`, `vendor`, `version`, `release`, `summary`, `description` |
| **OpenShift labels** | `io.k8s.display-name`, `io.k8s.description`, `io.openshift.tags` |
| **Health check** | Docker-native `HEALTHCHECK` on `/q/health/ready` |
| **Security scanning** | Trivy image scan in CI blocks push on OS-level CVEs |
| Requirement | Implementation |
| ---------------------- | ---------------------------------------------------------------------------------------------- |
| **Base image** | `registry.access.redhat.com/ubi9/openjdk-25-runtime:1.24` (pinned by SHA256 digest) |
Comment thread
ginccc marked this conversation as resolved.
Resolved
| **Non-root execution** | Runs as UID `185` — the default `jboss` user |
| **Licenses** | Auto-generated `/licenses` directory containing `THIRD-PARTY.txt` and downloaded license texts |
| **Required labels** | `name`, `vendor`, `version`, `release`, `summary`, `description` |
| **OpenShift labels** | `io.k8s.display-name`, `io.k8s.description`, `io.openshift.tags` |
| **Health check** | Docker-native `HEALTHCHECK` on `/q/health/ready` |
| **Security scanning** | Trivy image scan in CI blocks push on OS-level CVEs |

### Automated Certification Workflow

Expand All @@ -61,7 +61,7 @@ The certification release process is fully automated:

To trigger a certification release, go to **Actions → Red Hat Certification Release → Run workflow** and provide:

- `version` — EDDI version (e.g., `6.0.2`)
- `version` — EDDI version (e.g., `6.1.0`)
- `release` — Incremental release number (e.g., `1`, `2`, `3`)
- `submit` — Whether to submit results to Red Hat (`true`/`false`)
- `registry` — Target registry (`docker.io` or `quay.io`)
Expand All @@ -72,14 +72,14 @@ Every push to `main` or release tag that produces a Docker image is validated by

### Required GitHub Secrets

| Secret | Purpose |
|---|---|
| `REDHAT_API_TOKEN` | Pyxis API token from Red Hat Partner Connect |
| `REDHAT_CERT_PROJECT_ID` | Certification project ID |
| `DOCKER_USERNAME` | Docker Hub username |
| `DOCKER_PASSWORD` | Docker Hub password |
| `QUAY_USERNAME` | Quay.io robot account (optional, for Quay.io publishing) |
| `QUAY_PASSWORD` | Quay.io password (optional) |
| Secret | Purpose |
| ------------------------ | -------------------------------------------------------- |
| `REDHAT_API_TOKEN` | Pyxis API token from Red Hat Partner Connect |
| `REDHAT_CERT_PROJECT_ID` | Certification project ID |
| `DOCKER_USERNAME` | Docker Hub username |
| `DOCKER_PASSWORD` | Docker Hub password |
| `QUAY_USERNAME` | Quay.io robot account (optional, for Quay.io publishing) |
| `QUAY_PASSWORD` | Quay.io password (optional) |

---

Expand All @@ -93,11 +93,11 @@ Third-party licenses are generated on-demand using the `license-gen` Maven profi

This generates:

| File | Contents |
|---|---|
| File | Contents |
| -------------------------- | ------------------------------------------------- |
| `licenses/THIRD-PARTY.txt` | All runtime dependencies with their license names |
| `licenses/third-party/` | Downloaded license text files for each dependency |
| `licenses/licenses.xml` | Machine-readable license index |
| `licenses/third-party/` | Downloaded license text files for each dependency |
| `licenses/licenses.xml` | Machine-readable license index |

The profile is **not activated during normal dev builds** to keep them fast. CI workflows (`redhat-certify.yml`, `ci.yml`) activate it automatically.

Expand Down Expand Up @@ -147,16 +147,16 @@ The operator creates a route automatically. With the CR above, the route would b

## Docker Image Details

| Property | Value |
|---|---|
| **Image** | `docker.io/labsai/eddi` |
| **Base** | `registry.access.redhat.com/ubi9/openjdk-25-runtime:1.24` |
| **Digest pinning** | SHA256 digest for supply-chain integrity (OpenSSF Silver) |
| **User** | `185` (non-root) |
| **Port** | `7070` |
| **Health endpoint** | `GET /q/health/ready` |
| **Java** | OpenJDK 25 (Red Hat build) |
| **Framework** | Quarkus 3.34.x |
| Property | Value |
| ------------------- | --------------------------------------------------------- |
| **Image** | `docker.io/labsai/eddi` |
| **Base** | `registry.access.redhat.com/ubi9/openjdk-25-runtime:1.24` |
| **Digest pinning** | SHA256 digest for supply-chain integrity (OpenSSF Silver) |
| **User** | `185` (non-root) |
| **Port** | `7070` |
| **Health endpoint** | `GET /q/health/ready` |
| **Java** | OpenJDK 25 (Red Hat build) |
| **Framework** | Quarkus 3.34.x |

### Quick Start

Expand All @@ -171,5 +171,5 @@ For production deployments with MongoDB:
docker run -d \
-p 7070:7070 \
-e QUARKUS_MONGODB_CONNECTION_STRING=mongodb://mongo:27017 \
labsai/eddi:6.0.2
labsai/eddi:6.1.0
```
2 changes: 1 addition & 1 deletion helm/eddi/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ description: >-
and integrate with LLM providers via a unified REST API.
type: application
version: 1.0.0
appVersion: "6.0.2"
appVersion: "6.1.0"
home: https://eddi.labs.ai
sources:
- https://github.com/labsai/EDDI
Expand Down
Loading
Loading