> For the complete documentation index, see [llms.txt](https://docs.labs.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.labs.ai/archive/handoff-v6.0-snapshot.md).

# v6.0 Development Snapshot (archived)

> \[!CAUTION] **Do not follow anything on this page.** It is a frozen snapshot of early v6.0 development, last updated **2026-03-30**, kept only so the reasoning behind those decisions stays recoverable.
>
> It names classes that have been renamed (`LangchainTask` → `LlmTask`, `HttpCallsTask` → `ApiCallsTask`), REST paths that have moved, and phase plans that were superseded. It lived at the repository root until it was archived here, which meant AI coding assistants loaded 70 KB of stale identifiers as context on every session.
>
> **For anything current:**
>
> * [`docs/changelog.md`](/reference/changelog.md) — the authoritative log of changes and decisions
> * [`AGENTS.md`](https://github.com/labsai/EDDI/tree/main/AGENTS.md) — how to work in this codebase today
> * [`docs/architecture.md`](/architecture-and-concepts/architecture.md) — how the system is actually built

## Completed

### Phase 0: Security Quick Wins ✅ (commit `71448a89`)

* [x] CORS production to `localhost:3000,localhost:7070`
* [x] `PathNavigator` replaces all 5 explicit `Ognl.getValue()`/`Ognl.setValue()` calls
* [x] 27 new PathNavigator tests, all 499 tests pass

### Phase 1, Item 1: Extract `ConversationService` from `RestAgentEngine` ✅ (commit `7dd1488e`)

* [x] Created `IConversationService` interface with domain exceptions (no JAX-RS deps)
* [x] Created `ConversationService` implementation with all business logic (\~565 lines)
* [x] Refactored `RestAgentEngine` from 668 to \~230 lines (thin REST adapter)
* [x] 16 new unit tests for `ConversationService`
* [x] All 515 tests pass (0 failures, 0 errors, 4 skipped)

**Key files:**

* `src/main/java/ai/labs/eddi/engine/IConversationService.java`
* `src/main/java/ai/labs/eddi/engine/internal/ConversationService.java`
* `src/main/java/ai/labs/eddi/engine/internal/RestAgentEngine.java`
* `src/test/java/ai/labs/eddi/engine/internal/ConversationServiceTest.java`

### Phase 1, Item 2: Typed Memory Accessors ✅

* [x] Created `MemoryKey<T>` — type-safe key class with phantom type parameter and `isPublic` flag
* [x] Created `MemoryKeys` — central registry of well-known keys (`ACTIONS`, `INPUT`, `EXPRESSIONS_PARSED`, etc.)
* [x] Added typed accessor methods (`get`, `getData`, `getLatestData`, `set`) to `IConversationStep`, `IWritableConversationStep`, `IConversationStepStack`
* [x] Migrated 10 production files to use `MemoryKeys.*` constants
* [x] 15 new tests in `MemoryKeyTest`, updated 4 existing test files
* [x] All 533 tests pass (0 failures, 0 errors, 4 skipped)

**Key files:**

* `src/main/java/ai/labs/eddi/engine/memory/MemoryKey.java`
* `src/main/java/ai/labs/eddi/engine/memory/MemoryKeys.java`
* `src/main/java/ai/labs/eddi/engine/memory/IConversationMemory.java`
* `src/test/java/ai/labs/eddi/engine/memory/MemoryKeyTest.java`

### Phase 1, Item 3: Consolidate Configuration Stores ✅ (commit `201c5f99`)

* [x] Created `AbstractMongoResourceStore<T>` — generic base class with two constructors and 7 shared CRUD methods
* [x] Refactored 8 stores to extend base class: `LangChainStore`, `ParserStore`, `PropertySetterStore`, `HttpCallsStore`, `BehaviorStore`, `OutputStore`, `RegularDictionaryStore`, `AgentStore`, `WorkflowStore`
* [x] \~350 lines of duplicated delegation code eliminated
* [x] 7 new tests in `AbstractMongoResourceStoreTest`
* [x] All 540 tests pass (0 failures, 0 errors, 4 skipped)

**Key files:**

* `src/main/java/ai/labs/eddi/datastore/mongo/AbstractMongoResourceStore.java`
* `src/test/java/ai/labs/eddi/datastore/mongo/AbstractMongoResourceStoreTest.java`

### Phase 1, Item 4: Centralize REST Error Handling ✅ (commit `d4ab62bd`)

* [x] Created 4 JAX-RS `ExceptionMapper`s: `ResourceNotFoundExceptionMapper` (404), `ResourceStoreExceptionMapper` (500), `ResourceModifiedExceptionMapper` (409), `ResourceAlreadyExistsExceptionMapper` (409)
* [x] Created `SneakyThrow` utility for rethrowing checked exceptions as unchecked (avoids touching 50+ files to change exception hierarchy)
* [x] Refactored 22 REST classes to use `sneakyThrow` instead of manual exception translation
* [x] Net reduction of 91 lines of boilerplate error handling code
* [x] All 540 tests pass (0 failures, 0 errors, 4 skipped)

**Key files:**

* `src/main/java/ai/labs/eddi/engine/exception/SneakyThrow.java`
* `src/main/java/ai/labs/eddi/engine/exception/Resource*ExceptionMapper.java` (4 files)

### Phase 1, Item 5: Streaming API (SSE endpoint, `StreamingChatModel`) ✅

* [x] Two-layer SSE streaming: pipeline step events (`task_start`/`task_complete`) + LLM token events (`token`)
* [x] `ConversationEventSink` callback interface for all SSE event types
* [x] `ILanguageModelBuilder.buildStreaming()` in 4 builders (OpenAI, Anthropic, Gemini, Ollama)
* [x] `ChatModelRegistry.getOrCreateStreaming()` with separate streaming cache
* [x] `LifecycleManager` emits step events around each `task.execute()` call
* [x] `StreamingLegacyChatExecutor` bridges langchain4j async streaming with sync lifecycle (CountDownLatch)
* [x] `LangchainTask` detects streaming via `memory.getEventSink()`, delegates to streaming or sync path
* [x] `POST /agents/{env}/{agentId}/{convId}/stream` SSE endpoint (`RestAgentEngineStreaming`)
* [x] `ConversationService.sayStreaming()` with event sink adapter
* [x] 22 new tests across 5 test files
* [x] All \~562 tests pass (0 failures, 0 errors, 4 skipped)

**Key files:**

* `src/main/java/ai/labs/eddi/engine/lifecycle/ConversationEventSink.java`
* `src/main/java/ai/labs/eddi/modules/langchain/impl/StreamingLegacyChatExecutor.java`
* `src/main/java/ai/labs/eddi/engine/IRestAgentEngineStreaming.java`
* `src/main/java/ai/labs/eddi/engine/internal/RestAgentEngineStreaming.java`
* `src/test/java/ai/labs/eddi/modules/langchain/impl/StreamingLegacyChatExecutorTest.java`
* `src/test/java/ai/labs/eddi/modules/langchain/impl/ChatModelRegistryTest.java`
* `src/test/java/ai/labs/eddi/engine/lifecycle/internal/LifecycleManagerStreamingTest.java`

### Phase 1, Item 6: Decompose `LangchainTask` ✅

* [x] Created `ChatModelRegistry` — model creation, caching, and lookup
* [x] Created `ConversationHistoryBuilder` — memory → ChatMessage list conversion
* [x] Created `LegacyChatExecutor` — simple chat mode (no tools)
* [x] Created `AgentOrchestrator` — tool-calling agent loop with budget/rate-limiting
* [x] Refactored `LangchainTask` from 592→252 lines (thin orchestrator)
* [x] Trimmed `AgentExecutionHelper` from 223→140 lines (retry-only utility)
* [x] 16 new tests in `AgentOrchestratorTest`
* [x] All 540 tests pass (0 failures, 0 errors, 4 skipped)

**Key files:**

* `src/main/java/ai/labs/eddi/modules/langchain/impl/ChatModelRegistry.java`
* `src/main/java/ai/labs/eddi/modules/langchain/impl/ConversationHistoryBuilder.java`
* `src/main/java/ai/labs/eddi/modules/langchain/impl/LegacyChatExecutor.java`
* `src/main/java/ai/labs/eddi/modules/langchain/impl/AgentOrchestrator.java`
* `src/main/java/ai/labs/eddi/modules/langchain/impl/LangchainTask.java`

### Phase 2: Testing Infrastructure ✅ (commit `0956cefd`)

* [x] Migrated all integration tests from `EDDI-integration-tests` repo into main EDDI repo
* [x] Created `BaseIntegrationIT` with shared helpers (resource creation, deployment, cleanup)
* [x] Created `IntegrationTestProfile` with DevServices MongoDB (Testcontainers)
* [x] `AgentEngineIT` (11 tests): welcome, input, context, output, undo/redo, templating, property
* [x] `AgentDeploymentComponentIT` (4 tests): deploy, undeploy, status transitions
* [x] `ConversationServiceComponentIT` (7 tests): lifecycle, undo/redo, concurrent conversations
* [x] `ApiContractIT` (10 tests): CRUD contracts for behavior, dictionary, output, package, agent stores
* [x] `AgentUseCaseIT` (2 tests): weather agent import + managed agent API
* [x] CRUD ITs: `BehaviorCrudIT` (4), `DictionaryCrudIT` (5), `OutputCrudIT` (5)
* [x] Unit test gaps: `AgentFactoryTest`, `BehaviorRulesEvaluationTaskTest`, `RestAgentEngineTest`, `ConversationHistoryBuilderTest`, `LegacyChatExecutorTest`
* [x] Fixed `RestInterfaceFactory` port hardcoded to 7070 → now `@ConfigProperty` injected
* [x] Weather agent analysis: **confirmed v6.0 compatible** (no backwards compat issue, no migration needed)
* [x] All 48 integration tests + 620 unit tests = 668 tests pass

> **Note:** `EDDI-integration-tests` repo is now fully superseded. All tests migrated into main repo.

### Phase 3: API Consistency Fixes (N.7) ✅

* [x] **N.7.1** — Verified `restVersionInfo.create()` returns 201; duplicate POST 200 was Vite proxy issue. No backend change needed.
* [x] **N.7.2** — Added `?permanent=true` query parameter to all 8 store DELETE endpoints (interfaces + implementations). Default stays soft-delete.
* [x] **N.7.3** — `getDeploymentStatus` now returns JSON `{"status":"READY"}` by default. `?format=text` backward compat. Updated `TestCaseRuntime`, all integration tests, and Manager integration tests.
* [x] **N.7.4** — Deferred — Quarkus dev-mode HTML health response; `/q/health/live` workaround sufficient.

**Key files:**

* `IRestAgentAdministration.java`, `RestAgentAdministration.java` — deployment status JSON
* `RestVersionInfo.java` — `delete(id, version, permanent)` overload
* All 8 `IRest*Store` interfaces and `Rest*Store` implementations — `?permanent` param
* All integration tests updated for JSON deployment status

### Chat UI Vite Build + Agent Father Enhancements ✅

* [x] Deployed new Vite chat-ui production build to `META-INF/resources/` (replaces old CRA build)
* [x] `chat.html` updated for new Vite bundle entry points
* [x] Agent Father OpenAI flow: added timeout, built-in tools (whitelist), and conversation history limit steps
* [x] `OpenAILanguageModelBuilder`: migrated to `JdkHttpClient.builder()`
* [x] `GeminiLanguageModelBuilder`, `OllamaLanguageModelBuilder`: also migrated to JDK HttpClient

### Phase 5, Items 5.27-5.28: Event Bus Abstraction + NATS JetStream Adapter ✅ (commit `e220f4c0`)

* [x] Created `IEventBus` interface — abstract event bus for conversation ordering
* [x] Refactored `IConversationCoordinator` to extend `IEventBus` (backward compatible)
* [x] Renamed `ConversationCoordinator` → `InMemoryConversationCoordinator` (`@DefaultBean`)
* [x] Created `NatsConversationCoordinator` — JetStream durable ordering, `@LookupIfProperty(eddi.messaging.type=nats)`
* [x] Created `NatsHealthCheck` — Quarkus readiness check at `/q/health/ready`
* [x] Created `NatsMetrics` — Micrometer counters/timers for publish/consume
* [x] Added `io.nats:jnats` 2.25.2 dependency
* [x] Added `eddi.messaging.type` config (`in-memory` default, `nats` option)
* [x] Added `docker-compose.nats.yml` for local NATS JetStream development
* [x] Fixed pre-existing `javax.validation.constraints.NotNull` import in `RegularDictionaryConfiguration`
* [x] 8 new `NatsConversationCoordinatorTest` unit tests
* [x] All 639 tests pass (0 failures, 0 errors, 4 skipped)

**Key files:**

* `src/main/java/ai/labs/eddi/engine/runtime/IEventBus.java`
* `src/main/java/ai/labs/eddi/engine/runtime/internal/InMemoryConversationCoordinator.java`
* `src/main/java/ai/labs/eddi/engine/runtime/internal/NatsConversationCoordinator.java`
* `src/main/java/ai/labs/eddi/engine/runtime/internal/NatsHealthCheck.java`
* `src/main/java/ai/labs/eddi/engine/runtime/internal/NatsMetrics.java`
* `docker-compose.nats.yml`

### Phase 5, Item 5.29: Async Conversation Processing ✅

* [x] Dead-letter handling: retry up to `maxRetries`, then route to `EDDI_DEAD_LETTERS` stream (30-day retention)
* [x] `NatsMetrics` wired into coordinator (publish/consume/dead-letter counters and timers)
* [x] `RetryableCallable` wrapper for per-task retry tracking
* [x] Dead-letter stream created during `start()` with `Limits` retention
* [x] `eddi.nats.dead-letter-stream-name` config property added
* [x] `org.testcontainers:testcontainers:2.0.3` + `testcontainers-junit-jupiter:2.0.3` added
* [x] 12 unit tests in `NatsConversationCoordinatorTest` (+4 new)
* [x] 5 Testcontainers integration tests in `NatsConversationCoordinatorIT`
* [x] All 643 tests pass (0 failures, 0 errors, 4 skipped)

### Phase 5, Item 5.30: Coordinator Dashboard + Dead-Letter Admin ✅

* [x] `IConversationCoordinator` — default methods for status introspection + dead-letter management
* [x] `InMemoryConversationCoordinator` — retry logic (3 attempts), dead-letter queue, processed/dead-lettered counters
* [x] `NatsConversationCoordinator` — status methods, dead-letter listing (JetStream), stream purge
* [x] `CoordinatorStatus` + `DeadLetterEntry` DTO records
* [x] `IRestCoordinatorAdmin` + `RestCoordinatorAdmin` — REST API + SSE stream at `/administration/coordinator/`
* [x] Manager: Coordinator page at `/manage/coordinator` (status cards, queue depths, dead-letter admin table)
* [x] Manager: API module, TanStack Query hooks with SSE, sidebar nav, MSW handlers, i18n (11 locales)
* [x] `RestCoordinatorAdminTest` (10 tests), `InMemoryConversationCoordinatorTest` (12 tests), `coordinator.test.tsx` (12 tests)
* [x] Backend: 665 tests pass, Manager: 176 tests pass

**Key files (backend):**

* `src/main/java/ai/labs/eddi/engine/IRestCoordinatorAdmin.java`
* `src/main/java/ai/labs/eddi/engine/internal/RestCoordinatorAdmin.java`
* `src/main/java/ai/labs/eddi/engine/model/CoordinatorStatus.java`
* `src/main/java/ai/labs/eddi/engine/model/DeadLetterEntry.java`
* `src/main/java/ai/labs/eddi/engine/runtime/IConversationCoordinator.java`
* `src/main/java/ai/labs/eddi/engine/runtime/internal/InMemoryConversationCoordinator.java`
* `src/main/java/ai/labs/eddi/engine/runtime/internal/NatsConversationCoordinator.java`

**Key files (Manager):**

* `src/pages/coordinator.tsx`, `src/lib/api/coordinator.ts`, `src/hooks/use-coordinator.ts`

### Phase 6, Item 6.30: Repository Interface Abstraction ✅ (commit `e8d09f77`)

* [x] Created `IResourceStorageFactory` — factory interface for creating DB-agnostic storage backends
* [x] Created `MongoResourceStorageFactory` — MongoDB impl (`@DefaultBean`), single injection point for `MongoDatabase`
* [x] Created `AbstractResourceStore<T>` — DB-agnostic base class for config stores (replaces `AbstractMongoResourceStore`)
* [x] Relocated `HistorizedResourceStore<T>` from `datastore.mongo` → `datastore` package (zero MongoDB deps)
* [x] Relocated `ModifiableHistorizedResourceStore<T>` from `datastore.mongo` → `datastore` package
* [x] `AbstractMongoResourceStore<T>` — now extends `AbstractResourceStore`, marked `@Deprecated`
* [x] `mongo.HistorizedResourceStore` / `mongo.ModifiableHistorizedResourceStore` — thin backward-compat wrappers
* [x] Added `@DefaultBean` to `ConversationMemoryStore` (allows future PostgreSQL override)
* [x] Added `eddi.datastore.type=mongodb` config property to `application.properties`
* [x] 19 new tests: `HistorizedResourceStoreTest` (10), `AbstractResourceStoreTest` (7), `MongoResourceStorageFactoryTest` (2)
* [x] All 684 tests pass (0 failures, 0 errors, 4 skipped)

**Key files (new):**

* `src/main/java/ai/labs/eddi/datastore/IResourceStorageFactory.java`
* `src/main/java/ai/labs/eddi/datastore/mongo/MongoResourceStorageFactory.java`
* `src/main/java/ai/labs/eddi/datastore/AbstractResourceStore.java`
* `src/main/java/ai/labs/eddi/datastore/HistorizedResourceStore.java`
* `src/main/java/ai/labs/eddi/datastore/ModifiableHistorizedResourceStore.java`

**Key files (modified):**

* `src/main/java/ai/labs/eddi/datastore/mongo/AbstractMongoResourceStore.java` — extends AbstractResourceStore, @Deprecated
* `src/main/java/ai/labs/eddi/engine/memory/ConversationMemoryStore.java` — added @DefaultBean

### Phase 6, Item 6.31: PostgreSQL Adapter ✅

* [x] Added Maven dependencies: `quarkus-jdbc-postgresql`, `quarkus-agroal`, `testcontainers:postgresql`
* [x] Created `PostgresResourceStorage<T>` — JDBC + JSONB implementation of `IResourceStorage<T>`
  * Auto-creates `resources` + `resources_history` tables via `CREATE TABLE IF NOT EXISTS`
  * Uses `IJsonSerialization` for clean JSON↔object conversion
  * UUID-based IDs, version tracking, soft-delete support
* [x] Created `PostgresResourceStorageFactory` — `@LookupIfProperty(eddi.datastore.type=postgres)`
* [x] Created `PostgresHealthCheck` — readiness check at `/q/health/ready`
* [x] Migrated 7 stores from `AbstractMongoResourceStore` → `AbstractResourceStore` + `IResourceStorageFactory`: `LangChainStore`, `ParserStore`, `PropertySetterStore`, `HttpCallsStore`, `BehaviorStore`, `OutputStore`, `RegularDictionaryStore`
* [x] `AgentStore`/`WorkflowStore` now also migrated to `AbstractResourceStore` + `IResourceStorageFactory`
* [x] Added PostgreSQL datasource config to `application.properties` (inactive by default)
* [x] Created `docker-compose.postgres.yml` for local development
* [x] 15 new tests: `PostgresResourceStorageTest` (12), `PostgresResourceStorageFactoryTest` (3)
* [x] All 699 tests pass (0 failures, 0 errors, 4 skipped)

**Key files (new):**

* `src/main/java/ai/labs/eddi/datastore/postgres/PostgresResourceStorage.java`
* `src/main/java/ai/labs/eddi/datastore/postgres/PostgresResourceStorageFactory.java`
* `src/main/java/ai/labs/eddi/datastore/postgres/PostgresHealthCheck.java`
* `docker-compose.postgres.yml`

**Key files (migrated):**

* `src/main/java/ai/labs/eddi/configs/langchain/mongo/LangChainStore.java`
* `src/main/java/ai/labs/eddi/configs/parser/mongo/ParserStore.java`
* `src/main/java/ai/labs/eddi/configs/propertysetter/mongo/PropertySetterStore.java`
* `src/main/java/ai/labs/eddi/configs/http/mongo/HttpCallsStore.java`
* `src/main/java/ai/labs/eddi/configs/behavior/mongo/BehaviorStore.java`
* `src/main/java/ai/labs/eddi/configs/output/mongo/OutputStore.java`
* `src/main/java/ai/labs/eddi/configs/regulardictionary/mongo/RegularDictionaryStore.java`

### Phase 6, Item 6.32: Full Store Migration — All Stores DB-Agnostic ✅

* [x] Added `findResourceIdsContaining()`, `findHistoryResourceIdsContaining()`, `findResources()` to `IResourceStorage`
* [x] Implemented in `MongoResourceStorage` (MongoDB `$in`, regex, pagination)
* [x] Implemented in `PostgresResourceStorage` (JSONB `@>`, `~`, SQL pagination)
* [x] `AgentStore` migrated from `AbstractMongoResourceStore` → `AbstractResourceStore` + `IResourceStorageFactory`
* [x] `WorkflowStore` — same migration pattern, removed inner MongoDB classes
* [x] Created `IDeploymentStorage` interface (DB-agnostic)
* [x] Created `MongoDeploymentStorage` (`@DefaultBean`) — extracted MongoDB logic from DeploymentStore
* [x] Created `PostgresDeploymentStorage` (`@LookupIfProperty`) — JDBC with `INSERT...ON CONFLICT`, dedicated `deployments` table
* [x] `DeploymentStore` — refactored to thin delegate to `IDeploymentStorage`
* [x] Created DB-agnostic `DescriptorStore` in `datastore` package (uses `IResourceStorageFactory` + `IResourceStorage.findResources()`)
* [x] Updated `DocumentDescriptorStore`, `ConversationDescriptorStore`, `TestCaseDescriptorStore` to use `IResourceStorageFactory`
* [x] Created `PostgresConversationMemoryStore` — JSONB storage with indexed columns (agent\_id, agent\_version, conversation\_state)
* [x] All 701 tests pass (0 failures, 0 errors, 4 skipped). `mvnw verify` succeeds.

**Key files (new):**

* `src/main/java/ai/labs/eddi/configs/deployment/IDeploymentStorage.java`
* `src/main/java/ai/labs/eddi/configs/deployment/mongo/MongoDeploymentStorage.java`
* `src/main/java/ai/labs/eddi/datastore/DescriptorStore.java`
* `src/main/java/ai/labs/eddi/datastore/postgres/PostgresDeploymentStorage.java`
* `src/main/java/ai/labs/eddi/datastore/postgres/PostgresConversationMemoryStore.java`

**Key files (modified):**

* `AgentStore.java`, `WorkflowStore.java` — extends `AbstractResourceStore`
* `DeploymentStore.java` — thin delegate to `IDeploymentStorage`
* `DocumentDescriptorStore.java`, `ConversationDescriptorStore.java`, `TestCaseDescriptorStore.java` — use `IResourceStorageFactory`
* `IResourceStorage.java`, `MongoResourceStorage.java`, `PostgresResourceStorage.java` — new query methods

### Phase 6A: MongoDB Sync Driver Migration ✅

* [x] Replaced `mongodb-driver-reactivestreams` + RxJava3 with `mongodb-driver-sync`
* [x] Migrated 13 files from `Observable.fromPublisher(...).blocking*()` to direct sync API calls
* [x] Removed `io.reactivex.rxjava3` dependency
* [x] All tests pass

### Phase 6B: PostgreSQL Integration Test Parity ✅ (commit `0eda70d9`, `e77b6f23`)

* [x] Created `PostgresIntegrationTestProfile` with `eddi.datastore.type=postgres` + Testcontainers DevServices
* [x] Created 8 PostgreSQL IT subclasses — all 48/48 tests pass, full parity with MongoDB:
  * `PostgresBehaviorCrudIT` (4/4), `PostgresOutputCrudIT` (5/5), `PostgresDictionaryCrudIT` (5/5)
  * `PostgresAgentEngineIT` (11/11), `PostgresAgentDeploymentComponentIT` (4/4)
  * `PostgresConversationServiceComponentIT` (7/7), `PostgresApiContractIT` (10/10)
  * `PostgresAgentUseCaseIT` (2/2)
* [x] Fixed `RestUtilities.isValidId()` — added `-` for UUID dashes (`e5c68a0b`)
* [x] Fixed `DocumentDescriptorFilter` — added `isResourceIdValid()` guard on PUT/PATCH (`e5c68a0b`)
* [x] Added `#uuidUtils.extractId()` + `extractVersion()` to `UUIDWrapper` — DB-agnostic URI parsing (`7fb79bfa`)
* [x] Updated all 7 Agent Father httpcalls JSONs (70 replacements) + re-zipped `Agent+Father-4.0.0.zip`
* [x] Added 12 unit tests in `UUIDWrapperTest`
* [x] Documented `#uuidUtils` in `docs/output-templating.md`
* [x] Fixed `PostgresIntegrationTestProfile` — added `quarkus.http.port=8082` for `RestInterfaceFactory` (`0eda70d9`)
* [x] Fixed `PostgresApiContractIT` — overrode `readNonExistent_returns404` with UUID-formatted ID (`0eda70d9`)
* [x] Fixed `AgentUseCaseIT.useAgentManagement` — stale trigger cleanup + status assertions (`e77b6f23`)
* [x] All 96 integration tests pass (48 MongoDB + 48 PostgreSQL)

**Key files:**

* `src/main/java/ai/labs/eddi/utils/RestUtilities.java` — `isValidId()` UUID fix
* `src/main/java/ai/labs/eddi/engine/runtime/rest/interceptors/DocumentDescriptorFilter.java` — `isResourceIdValid` guard
* `src/main/java/ai/labs/eddi/modules/templating/impl/dialects/uuid/UUIDWrapper.java` — `extractId/extractVersion`
* `src/main/resources/initial-agents/Agent+Father-4.0.0.zip` — re-zipped with updated httpcalls
* `src/test/java/ai/labs/eddi/integration/PostgresIntegrationTestProfile.java` — PG test profile
* `src/test/java/ai/labs/eddi/integration/postgres/` — 8 PG IT subclasses
* `src/test/java/ai/labs/eddi/integration/AgentUseCaseIT.java` — stale trigger cleanup
* `docs/output-templating.md` — `#uuidUtils` documentation

### Agent Lifecycle API: Cascade Delete + Orphan Detection ✅

* [x] Added `?cascade=true` to `DELETE /agentstore/agents/{id}` and `DELETE /packagestore/packages/{id}`
* [x] Cascade walks agent → packages → extensions and deletes all children
* [x] **Shared-resource safety**: checks references before deleting — skips packages used by other agents, extensions used by other packages
* [x] Added `IResourceClientLibrary.deleteResource(URI, permanent)` for cascade use
* [x] New admin endpoint: `GET/DELETE /administration/orphans`
  * GET: scans all 8 store types for unreferenced resources (dry-run report)
  * DELETE: permanently purges all orphans
  * Algorithm: enumerate agents → packages → extensions → compare against all descriptors per store
* [x] DTOs: `OrphanInfo`, `OrphanReport`; interfaces: `IRestOrphanAdmin`, `IRestAgentStore`, `IRestWorkflowStore` updated
* [x] Enriched OpenAPI annotations with `@Operation`, `@Parameter`, `@APIResponse` descriptions
* [x] Documentation: deletion + orphan sections in `docs/deployment-management-of-agents.md`
* [x] Tests: `RestAgentStoreTest` (6/6), `RestWorkflowStoreTest` (7/7), `RestOrphanAdminTest` (4/4) — 17 new tests total
* [x] Full test suite passes

**Key files (new):**

* `src/main/java/ai/labs/eddi/configs/admin/model/OrphanInfo.java`
* `src/main/java/ai/labs/eddi/configs/admin/model/OrphanReport.java`
* `src/main/java/ai/labs/eddi/configs/admin/IRestOrphanAdmin.java`
* `src/main/java/ai/labs/eddi/configs/admin/rest/RestOrphanAdmin.java`
* `src/test/java/ai/labs/eddi/configs/admin/rest/RestOrphanAdminTest.java`
* `src/test/java/ai/labs/eddi/configs/agents/rest/RestAgentStoreTest.java`
* `src/test/java/ai/labs/eddi/configs/packages/rest/RestWorkflowStoreTest.java`

**Key files (modified):**

* `IRestAgentStore.java`, `RestAgentStore.java` — cascade + shared-resource check
* `IRestWorkflowStore.java`, `RestWorkflowStore.java` — cascade + shared-resource check
* `IResourceClientLibrary.java`, `ResourceClientLibrary.java` — `deleteResource` method
* `docs/deployment-management-of-agents.md` — deletion + orphan docs

### Phase 6C: Infinispan → Caffeine ✅

* [x] Rewrote `CacheFactory.java` — Caffeine builder with inline size configs (replaced `EmbeddedCacheManager`)
* [x] Rewrote `CacheImpl.java` — wraps Caffeine `Cache<K,V>` (replaced Infinispan `Cache`)
* [x] Removed 4 Infinispan dependencies + `infinispan.version` property from POM
* [x] Caffeine provided transitively by `quarkus-cache` (already in POM)
* [x] Deleted `infinispan-embedded.xml` config
* [x] Cleaned `application.properties` (removed 2 Infinispan config lines)
* [x] Updated `ToolCacheService` Javadoc + log message
* [x] Verified: multi-instance agent deployment does NOT use Infinispan (uses DB-backed `IDeploymentStore` + `@Scheduled` polling)
* [x] 729 unit tests pass (0 failures, 0 errors, 4 skipped)

**Key files:**

* `src/main/java/ai/labs/eddi/engine/caching/CacheFactory.java` — rewritten
* `src/main/java/ai/labs/eddi/engine/caching/CacheImpl.java` — rewritten
* `pom.xml` — 4 deps removed, caffeine via quarkus-cache
* `src/main/resources/infinispan-embedded.xml` — deleted
* `src/main/resources/application.properties` — cleaned

### Phase 6E: quarkus-langchain4j → langchain4j Core ✅

* [x] Removed 6 `io.quarkiverse.langchain4j` dependencies from POM
* [x] Added 7 core `dev.langchain4j` deps (langchain4j, open-ai, anthropic, ollama, vertex-ai-gemini, hugging-face, jlama)
* [x] Removed `quarkus.langchain4j.version` property, added `langchain4j-beta.version` (1.11.0-beta19) for beta-versioned modules
* [x] Migrated `VertexGeminiLanguageModelBuilder`: new package (`vertexai.gemini`), API renames, removed `timeout()` (now EDDI-level)
* [x] Migrated `HuggingFaceLanguageModelBuilder`: removed quarkiverse-only methods (`topK`, `topP`, `doSample`, `repetitionPenalty`), kept core methods only
* [x] Migrated `JlamaLanguageModelBuilder`: package change only, removed unsupported `logRequests`/`logResponses`
* [x] Created `ObservableChatModel` — provider-agnostic ChatModel decorator with configurable timeout + request/response logging
* [x] Wired into `ChatModelRegistry.getOrCreate()` — all providers get timeout+logging automatically via `timeout`, `logRequests`, `logResponses` config params
* [x] Zero `quarkiverse` references in dependency tree
* [x] 753 unit tests pass (0 failures, 0 errors, 4 skipped) — 19 `ObservableChatModelTest` + 5 `ChatModelRegistryTest` observability tests

**Key files:**

* `pom.xml` — 6 deps removed, 7 added, version properties updated
* `src/main/java/.../impl/ObservableChatModel.java` — **NEW** provider-agnostic timeout + logging decorator
* `src/main/java/.../impl/ChatModelRegistry.java` — wires ObservableChatModel
* `src/main/java/.../builder/VertexGeminiLanguageModelBuilder.java` — rewritten
* `src/main/java/.../builder/HuggingFaceLanguageModelBuilder.java` — rewritten
* `src/main/java/.../builder/JlamaLanguageModelBuilder.java` — updated
* `src/test/java/.../impl/ObservableChatModelTest.java` — **NEW** 19 tests
* `src/test/java/.../impl/ChatModelRegistryTest.java` — 5 new observability tests

### Phase 6D: Lombok Removal ✅ (commit `ca3e45da`)

* [x] IntelliJ delombok expanded all 114 files (107 main + 7 test)
* [x] Fixed 11 structurally corrupted files from field-level annotation script
* [x] `isIsPublic` → `isPublic` naming fix in `Data.java` and `ResultSnapshot`
* [x] Removed Lombok dependency, version property, and annotation processor from POM
* [x] All 775 tests pass, 0 Lombok annotations/imports remain

### Phase 7, Item 33: Secrets Vault — Security Remediation ✅

* [x] R1: Fixed CRITICAL memory leakage — PropertySetterTask no longer resolves vault refs to plaintext, HttpCallExecutor scrubs sensitive headers
* [x] R2: Complete URL/body/query resolution in HttpCallExecutor
* [x] R3: Secret input mechanism — `Property.Scope.secret` + auto-vault + `InputFieldOutputItem` with `subType: password`
* [x] R4: PBKDF2 key derivation — upgraded EnvelopeCrypto from SHA-256 to PBKDF2 (600K iterations)
* [x] R5: REST input validation — path param regex in RestSecretStore
* [x] R6: 32 unit tests across 5 test classes (9+7+6+4+6)
* [x] Fixed SecretRedactionFilter regex replacement bug ($ interpreted as group reference)
* [x] Fixed 8 pre-existing Lombok ghost-method bugs in OutputItem subclasses + OutputConfiguration
* [x] Cleanup: removed dead secretResolver, unused imports
* [x] Documentation: `docs/secrets-vault.md`
* [x] Installer integration: vault master key auto-generated during install, stored in `~/.eddi/.env`
* [x] All 810 tests pass (0 failures, 0 errors, 4 skipped)

**Key files (new):**

* `src/main/java/ai/labs/eddi/secrets/` — model, crypto, sanitize, rest packages
* `src/test/java/ai/labs/eddi/secrets/` — EnvelopeCryptoTest, SecretResolverTest, SecretRedactionFilterTest, SecretScrubberTest, SecretReferenceTest
* `docs/secrets-vault.md` — full feature documentation

**Key files (modified):**

* `PropertySetterTask.java` — secret scope auto-vault, removed dead secretResolver
* `HttpCallExecutor.java` — header scrubbing, vault ref resolution
* `RestExportService.java` — export sanitization
* `OutputConfiguration.java` + 6 OutputItem subclasses — Lombok bug fixes

### Phase 7, Item 34: Immutable Audit Ledger — EU AI Act Compliance ✅

* [x] Created `AuditEntry` record — per-task audit data with 18 fields (input, output, LLM detail, actions, cost, timing, HMAC)
* [x] Created `IAuditStore` interface — write-once contract (NO update/delete methods)
* [x] Created `AuditStore` (MongoDB) — `audit_ledger` collection, `insertOne`/`insertMany` only, 3 indexes
* [x] Created `AuditHmac` — HMAC-SHA256 integrity signing, PBKDF2 key derivation from vault master key (independent salt)
* [x] Created `AuditLedgerService` — async batch writer with re-queue retry (3 attempts), secret scrubbing, HMAC signing
* [x] Created `IAuditEntryCollector` — functional interface decoupling `LifecycleManager` from storage
* [x] Integrated into `LifecycleManager` — `buildAuditEntry()` emits audit entry per task completion
* [x] Integrated into `ConversationService` — both `say` and `sayStreaming` paths set audit collector with environment enrichment
* [x] Created `IRestAuditStore` / `RestAuditStore` — read-only REST API (`/auditstore/{conversationId}`, `/auditstore/agent/{agentId}`)
* [x] Added `AuditEntry.withEnvironment()` — environment enrichment at the ConversationService layer
* [x] Secret redaction via `SecretRedactionFilter.redact()` — recurses into nested maps and lists
* [x] HMAC determinism — `buildCanonicalString()` sorts map keys via `TreeMap`
* [x] Flush retry — entries re-queued on DB failure, capped at 3 retries before dropping
* [x] Created `PostgresAuditStore` — JDBC+JSONB hybrid storage, `@IfBuildProfile("postgres")`, same insert-only contract
* [x] LangchainTask audit integration — writes `audit:compiled_prompt`, `audit:model_response`, `audit:model_name` memory keys
* [x] Documentation: `docs/audit-ledger.md`
* [x] 20 unit tests in `AuditLedgerServiceTest`: queue/flush (4), HMAC (5), scrubbing (3), retry (3), entry helpers (2), determinism (1), canonical (2)

**Key files (new):**

* `src/main/java/ai/labs/eddi/engine/audit/model/AuditEntry.java`
* `src/main/java/ai/labs/eddi/engine/audit/IAuditStore.java`
* `src/main/java/ai/labs/eddi/engine/audit/IAuditEntryCollector.java`
* `src/main/java/ai/labs/eddi/engine/audit/AuditHmac.java`
* `src/main/java/ai/labs/eddi/engine/audit/AuditLedgerService.java`
* `src/main/java/ai/labs/eddi/engine/audit/AuditStore.java` (MongoDB)
* `src/main/java/ai/labs/eddi/datastore/postgres/PostgresAuditStore.java` (PostgreSQL)
* `src/main/java/ai/labs/eddi/engine/audit/rest/IRestAuditStore.java`
* `src/main/java/ai/labs/eddi/engine/audit/rest/RestAuditStore.java`
* `src/test/java/ai/labs/eddi/engine/audit/AuditLedgerServiceTest.java`
* `docs/audit-ledger.md`

**Key files (modified):**

* `IConversationMemory.java` / `ConversationMemory.java` — `getAuditCollector` / `setAuditCollector`
* `LifecycleManager.java` — `buildAuditEntry()` + audit hook
* `ConversationService.java` — injected `AuditLedgerService`, environment-enriched audit collector
* `LangchainTask.java` — writes `audit:*` memory keys after each LLM call
* `LangchainTaskTest.java` — updated storeData expected counts
* `ConversationServiceTest.java` — updated constructor

### Scheduled Triggers & Heartbeats ✅

Two trigger types on a shared engine:

| Trigger       | Config                     | Default Strategy                    | Next Fire Logic                |
| ------------- | -------------------------- | ----------------------------------- | ------------------------------ |
| **CRON**      | `cronExpression` (5-field) | `new` (fresh conversation per fire) | Recomputed from cron           |
| **HEARTBEAT** | `heartbeatIntervalSeconds` | `persistent` (single conversation)  | `now + interval` (drift-proof) |

**Exactly-once execution:** Atomic CAS via MongoDB `findOneAndUpdate` with `PENDING` + `nextRetryAt ≤ now` guards. Dead-lettering after configurable `maxRetries` with exponential backoff (`base × multiplier^failCount`).

**Engine flow:** `SchedulePollerService.poll()` → `tryClaim()` → `ScheduleFireExecutor.fire()` → `ConversationService.say()` → `markCompleted()` / `markFailed()` / `markDeadLettered()`

**MCP tools (6):** `create_schedule`, `list_schedules`, `read_schedule`, `delete_schedule`, `fire_schedule_now`, `retry_failed_schedule`

**Key files:**

* `src/main/java/ai/labs/eddi/configs/schedule/model/ScheduleConfiguration.java` — `TriggerType`, `FireStatus` enums
* `src/main/java/ai/labs/eddi/configs/schedule/mongo/MongoScheduleStore.java` — CAS, atomic ops, epoch-millis
* `src/main/java/ai/labs/eddi/engine/runtime/internal/SchedulePollerService.java` — poll + claim + backoff
* `src/main/java/ai/labs/eddi/engine/runtime/internal/ScheduleFireExecutor.java` — fire + context injection
* `src/main/java/ai/labs/eddi/configs/schedule/rest/RestScheduleStore.java` — REST + validation
* `src/main/java/ai/labs/eddi/engine/mcp/McpAdminTools.java` — 6 schedule MCP tools
* Tests: `SchedulePollerServiceTest` (12), `ScheduleFireExecutorTest` (9), `RestScheduleStoreTest` (13), `McpScheduleToolsTest` (21), `CronParserTest` (16), `CronDescriberTest` (8)

**Configuration (`application.properties`):**

```properties
eddi.schedule.enabled=true
eddi.schedule.poll-interval=30s
eddi.schedule.lease-timeout=5m
eddi.schedule.max-retries=5
eddi.schedule.backoff-base-seconds=15
eddi.schedule.backoff-multiplier=4
eddi.schedule.min-interval-seconds=60
```

**Agent ↔ Schedule Lifecycle Hooks:**

| Agent Event          | Schedule Effect                                           | Where                                                                       |
| -------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------- |
| **Deploy**           | Auto-enable all disabled schedules for agentId            | `RestAgentAdministration.enableSchedulesForAgent()`                         |
| **Undeploy**         | Auto-disable all enabled schedules for agentId            | `RestAgentAdministration.disableSchedulesForAgent()`                        |
| **Delete (cascade)** | Delete all schedules for agentId (before package cascade) | `RestAgentStore.deleteAgent()` → `scheduleStore.deleteSchedulesByAgentId()` |
| **Export**           | Include schedules as `{id}.schedule.json` in export ZIP   | `RestExportService.exportSchedules()`                                       |

All hooks are **non-fatal** — if schedule operations fail, the primary agent operation still succeeds (logged as warning).

**EDDI Manager:** No schedule UI yet. Backend REST API + MCP tools are the only interfaces.

### Phase 10: Group Conversations — Multi-Agent Debate Orchestration ✅

Phase-based orchestration engine enabling structured multi-agent discussions with 6 preset styles, nested group-of-groups support, and moderator synthesis.

| Sub-Phase                      | Deliverables                                                                            |
| ------------------------------ | --------------------------------------------------------------------------------------- |
| **10.1** Data Models + Stores  | `AgentGroupConfiguration`, `GroupConversation`, group/conversation stores (DB-agnostic) |
| **10.2** Orchestration Service | `GroupConversationService` (\~680 lines) — phases, context scoping, templates           |
| **10.3** REST + SSE + MCP      | REST endpoints, SSE streaming, `McpGroupTools` (9 tools)                                |
| **10.5** Discussion Styles     | `DiscussionPhase`, `DiscussionStylePresets` — 6 styles + custom phases                  |
| **10.5b** MCP/REST Usability   | `describe_discussion_styles`, `list_group_conversations`, `GET /styles`                 |
| **10.6** Group-of-Groups       | `MemberType.GROUP`, recursive `executeGroupMemberTurn()`, `memberTypes` param           |

**Discussion styles:** `ROUND_TABLE`, `PEER_REVIEW`, `DEVIL_ADVOCATE`, `DELPHI`, `DEBATE`, `TASK_FORCE` (+ fully custom phases)

**Group-of-Groups:** Members can be other groups — sub-group synthesized answer becomes member's response. Depth tracking prevents infinite recursion (`eddi.groups.max-depth`, default: 3).

**Tests:** 58 total

* `GroupConversationServiceTest` (17) — orchestration, all styles, recursion, error handling
* `McpGroupToolsTest` (22) — MCP tool layer
* `DiscussionStylePresetsTest` (19) — style expansion

**Key files:**

* `src/main/java/ai/labs/eddi/configs/groups/model/AgentGroupConfiguration.java`
* `src/main/java/ai/labs/eddi/configs/groups/model/GroupConversation.java`
* `src/main/java/ai/labs/eddi/configs/groups/model/DiscussionStylePresets.java`
* `src/main/java/ai/labs/eddi/engine/internal/GroupConversationService.java`
* `src/main/java/ai/labs/eddi/engine/mcp/McpGroupTools.java`
* `src/test/java/ai/labs/eddi/engine/internal/GroupConversationServiceTest.java`

### Templating Engine Migration: Thymeleaf → Quarkus Qute ✅

Replaced Thymeleaf 3.1.3 + OGNL 3.3.4 with Quarkus Qute for native image compatibility and CVE remediation.

| Component             | Key Files                                                                                                                      |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **Core Engine**       | `TemplatingEngine.java` — Qute `Engine` API with null-safety                                                                   |
| **Extensions**        | `EddiTemplateExtensions.java` (UUID, JSON, Encoder namespaces), `StringTemplateExtensions.java` (15 String methods)            |
| **Migrator**          | `TemplateSyntaxMigrator.java` — 10 regex patterns + close-tag scanner + string concat handler                                  |
| **Startup Migration** | `V6QuteMigration.java` — idempotent startup hook for 4 MongoDB collections (apicalls, outputs, propertysetter, llms + history) |
| **Import Migration**  | `RestImportService.java` — `TemplateSyntaxMigrator` wired as final-pass before deserialization                                 |

**Migration patterns:** `[[${var}]]` → `{var}`, `th:each` → `{#for}`, `th:if` → `{#if}`, `#strings.*` → native method calls, `#uuidUtils.`/`#json.`/`#encoder.` → namespace, `a + '/' + b` → `{a}/{b}`.

**Consumers updated:** `McpApiToolBuilder`, `AgentSetupService`, `DiscussionStylePresets` (10 templates), `PrePostUtils`, `ChatModelRegistry`, `MigrationManager`.

**Tests:** `TemplatingEngineTest` (20), `TemplateSyntaxMigratorTest` (29), `OutputTemplateTaskTest` (2), `McpApiToolBuilderTest` (14), `CreateApiAgentIT` (10).

**Docs updated:** `output-templating.md` (full rewrite), `architecture.md`, `httpcalls.md`, `conversation-memory.md`, `agent-father-deep-dive.md`, `changelog.md`.

**Config:**

```properties
eddi.migration.v6-qute.enabled=true   # Enable startup migration
quarkus.qute.strict-rendering=false    # Lenient variable handling
```

**Key files:**

* `src/main/java/ai/labs/eddi/modules/templating/impl/TemplatingEngine.java`
* `src/main/java/ai/labs/eddi/modules/templating/impl/extensions/EddiTemplateExtensions.java`
* `src/main/java/ai/labs/eddi/modules/templating/impl/extensions/StringTemplateExtensions.java`
* `src/main/java/ai/labs/eddi/configs/migration/TemplateSyntaxMigrator.java`
* `src/main/java/ai/labs/eddi/configs/migration/V6QuteMigration.java`
* `src/main/java/ai/labs/eddi/backup/impl/RestImportService.java`
* `src/test/java/ai/labs/eddi/configs/migration/TemplateSyntaxMigratorTest.java`
* `src/test/java/ai/labs/eddi/modules/templating/TemplatingEngineTest.java`
* `docs/output-templating.md`

### A2A Protocol: Agent-to-Agent Communication ✅

Implements the [A2A protocol](https://github.com/google/A2A) for distributed peer-to-peer agent communication.

| Component       | Key Files                                                                                    |
| --------------- | -------------------------------------------------------------------------------------------- |
| **A2A Models**  | `A2AModels.java` — Protocol records (AgentCard, JSON-RPC, Task, Artifact)                    |
| **Server**      | `AgentCardService.java` — Agent Card generation from `AgentConfiguration`                    |
|                 | `A2ATaskHandler.java` — JSON-RPC → `ConversationService.say()` bridge                        |
|                 | `RestA2AEndpoint.java` — `/.well-known/agent.json`, `/a2a/agents/{id}`                       |
| **Client**      | `A2AToolProviderManager.java` — Discovers remote agents, wraps skills as `ToolSpecification` |
| **Config**      | `AgentConfiguration` — `a2aEnabled`, `a2aSkills`, `description`                              |
|                 | `LlmConfiguration.Task` — `a2aAgents[]` with `A2AAgentConfig`                                |
| **Integration** | `AgentOrchestrator` + `LlmTask` — A2A tools merge with built-in/MCP/httpcall tools           |

**Config properties:**

```properties
eddi.a2a.enabled=true                         # Master toggle
eddi.a2a.base-url=http://localhost:7070        # Base URL for Agent Card URLs
```

**Security:** API keys must use vault references (`${vault:my-key}`). Runtime warning on raw key usage.

**Documentation:** `docs/a2a-protocol.md`

### Multi-Model Cascading Routing ✅ (commit `514821d4`)

Cost-optimized LLM execution via sequential model escalation with confidence-based routing.

* [x] `ModelCascadeConfig` + `CascadeStep` config schema on `LlmConfiguration.Task`
* [x] `CascadingModelExecutor` — cascade loop with per-step timeout, error escalation, SSE events
* [x] `ConfidenceEvaluator` — 4 strategies: `structured_output`, `heuristic`, `judge_model`, `none`
* [x] `ConversationEventSink` — `onCascadeStepStart` + `onCascadeEscalation` default methods
* [x] `LlmTask` integration — cascade branch with full backward compat
* [x] Audit trail: `audit:cascade_model`, `audit:cascade_confidence`, `cascade:trace`
* [x] 39 new tests: `ConfidenceEvaluatorTest` (22), `CascadingModelExecutorTest` (13), `LlmTaskTest` cascade (4)
* [x] All 1291 tests pass, 0 failures

**Key files:**

* `src/main/java/ai/labs/eddi/modules/llm/impl/CascadingModelExecutor.java` (NEW)
* `src/main/java/ai/labs/eddi/modules/llm/impl/ConfidenceEvaluator.java` (NEW)
* `src/main/java/ai/labs/eddi/modules/llm/model/LlmConfiguration.java`
* `src/main/java/ai/labs/eddi/engine/lifecycle/ConversationEventSink.java`
* `src/main/java/ai/labs/eddi/modules/llm/impl/LlmTask.java`
* `docs/model-cascade.md`

### LLM Structured Output Hardening ✅

Production-grade reliability for LLM structured JSON output via three-layer defense:

| Layer             | Mechanism                                                                                                                                                  |
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **System Prompt** | `## RESPONSE FORMAT (MANDATORY)` section appended when `convertToObject=true`. Includes exact schema if `responseSchema` parameter provided                |
| **API Level**     | `ChatRequest.responseFormat(ResponseFormatType.JSON)` for providers that support it (OpenAI, Gemini, Mistral). Graceful fallback for unsupported providers |
| **Validation**    | Pre-parse `startsWith("{")` check before `deserialize()`. Non-JSON stored as plain string with warning                                                     |

Additional fixes:

* [x] Raw LLM response persisted BEFORE JSON conversion (debuggability)
* [x] `jsonMode` flag derived from `convertToObject` (was incorrectly using `addToOutput`)
* [x] Prometheus tag conflicts in `ToolExecutionService` — removed tagless aggregate timer/counters
* [x] QR blank expression defense in `InputParserTask`

**Key files:**

* `LlmTask.java` — prompt reinforcement, raw storage, JSON validation, `responseSchema` param
* `LegacyChatExecutor.java` — `ChatRequest` with `ResponseFormat.JSON` + graceful fallback
* `ToolExecutionService.java` — per-tool tagged metrics only
* `InputParserTask.java` — blank expression guard

**Tests:** All 17 LlmTask tests pass. Compile verified.

## Next Up

### Quick Wins

* [x] ~~**Phase 6E: quarkus-langchain4j → langchain4j Core**~~ ✅
* [x] ~~**Phase 6D: Lombok Removal**~~ ✅
* [x] ~~**Quarkus 3.34.1 Upgrade**~~ ✅ — upgraded past 3.33 LTS to 3.34.1. Java 25 `ALL-UNNAMED` module issue resolved.

### Phase 7 (continued)

* [x] ~~Item 33: Secrets Vault~~ ✅
* [x] ~~Item 33b: Chat UI password field + Manager integration~~ ✅
* [x] ~~Item 34: Immutable Audit Ledger~~ ✅
* [x] ~~Item 34b: Tenant Quota Stub~~ ✅

### Phase 8a: MCP Servers ✅ (commits `1553b40e`, `b9a9c5e1`, latest)

* [x] `quarkus-mcp-server-http` v1.10.2 dependency
* [x] `McpConversationTools` — 7 tools (list\_agents, list\_agent\_configs, create\_conversation, talk\_to\_agent, **chat\_with\_agent**, read\_conversation, read\_conversation\_log)
* [x] `McpAdminTools` — 6 tools (deploy\_agent, undeploy\_agent, get\_deployment\_status, list\_packages, create\_agent, delete\_agent)
* [x] `McpSetupTools` — **setup\_agent** composite tool: creates full agent (behavior → langchain → output → package → agent → deploy) in a single MCP call
* [x] `McpSetupTools` — **create\_api\_agent** composite tool: OpenAPI spec → grouped HttpCalls → behavior → langchain → package → agent → deploy
* [x] `McpApiToolBuilder` — OpenAPI 3.0/3.1 parser: tag-based grouping, endpoint filtering, path/query param → Thymeleaf conversion, body templates, deprecated op skipping
* [x] `McpToolUtils` — shared helpers, RFC 8259 JSON escaping, `extractIdFromLocation`/`extractVersionFromLocation`
* [x] `swagger-parser` v2.1.39 dependency
* [x] Default model: `anthropic`/`claude-sonnet-4-6` (was `openai`/`gpt-4o`)
* [x] 75 unit tests (18 McpToolUtils + 16 Conversation + 16 Admin + 17 Setup + 19 ApiToolBuilder) — Code review: 5 fixes applied
* [x] `CreateApiAgentIT` — 10 ordered REST API tests (standalone, not @QuarkusTest due to MCP extension limitation)
* [x] Streamable HTTP transport at `/mcp`
* [x] `docs/mcp-server.md` with Claude Desktop config + setup tools reference
* [x] Code review fixes: `@Blocking`, error callback, typed params, `resolveParams()` extraction, static Pattern, prompt enrichment ArgumentCaptor test
* [x] **MCP Improvements** (2026-03-18):
  * AI-agent-friendly responses: `buildConversationResponse()` extracts `agentResponse`, `quickReplies`, `actions`, `conversationState` as top-level fields
  * Ollama/jlama support: all 7 providers in `setup_agent`, `baseUrl` param, `isLocalLlmProvider()` skips apiKey validation, provider-specific param mapping
  * Deploy verification: `deployAndWait()` polls deployment status for 5s, reports actual status + warning on failure
  * `OllamaLanguageModelBuilder` — added `baseUrl` support to both `build()` and `buildStreaming()`
  * `docker-compose.yml` — added `host.docker.internal:host-gateway` for Docker-hosted Ollama
  * 38 MCP tests pass (16 McpConversationToolsTest + 22 McpSetupToolsTest)

**Key files:**

* `src/main/java/ai/labs/eddi/engine/mcp/McpConversationTools.java`
* `src/main/java/ai/labs/eddi/engine/mcp/McpAdminTools.java`
* `src/main/java/ai/labs/eddi/engine/mcp/McpSetupTools.java`
* `src/main/java/ai/labs/eddi/engine/mcp/McpApiToolBuilder.java`
* `src/main/java/ai/labs/eddi/engine/mcp/McpToolUtils.java`
* `src/test/java/ai/labs/eddi/engine/mcp/McpSetupToolsTest.java` (+ 3 other test files)
* `src/test/java/ai/labs/eddi/integration/CreateApiAgentIT.java`
* `docs/mcp-server.md`

### Phase 8a (continued): MCP Code Review, Resource Tools, Docs MCP Resources ✅

* [x] **Code review fixes**:
  * Fixed `get_agent` N+1 query → direct `readDescriptor(id, ver)` call
  * Fixed `deployAgent` response → `deployed` consistently boolean (was `"pending"` string for 202)
  * Fixed `ConversationState` import → moved to `engine.model`
  * Fixed `McpToolFilter` missing imports (`ToolManager.ToolInfo`, `FilterContext`)
  * Deduplicated `getRestStore()` → shared in `McpToolUtils` (3 classes now delegate)
* [x] **Simplified `update_agent`** — now only updates name/description via `patchDescriptor()` + optional redeploy. Removed package add/remove business logic (wrong abstraction level).
* [x] **New tools**: `read_package`, `read_resource` (thin REST delegates for inspecting agent internals)
* [x] **`McpToolFilter`** whitelist updated: 18 → 20 tools
* [x] **`McpDocResources.java`** — NEW: exposes docs as MCP resources (`eddi://docs/index`, `eddi://docs/{name}`)
* [x] **`Dockerfile.jvm`** — COPY docs into container, `eddi.docs.path=/deployments/docs`
* [x] **`mcp-server.md`** — rewritten: all 20 tools (snake\_case), tool filtering, auth, sentiment monitoring, MCP resources sections
* [x] 116 MCP tests pass (0 failures)

**Key files (new):**

* `src/main/java/ai/labs/eddi/engine/mcp/McpDocResources.java`

**Key files (modified):**

* `McpConversationTools.java` — N+1 fix, ConversationState import, removed unused import
* `McpAdminTools.java` — simplified `update_agent`, added `read_package` + `read_resource`
* `McpToolUtils.java` — shared `getRestStore()`
* `McpSetupTools.java` — delegate `getRestStore()`, removed unused import
* `McpToolFilter.java` — whitelist 18→20, added missing imports
* `Dockerfile.jvm` — docs COPY + `eddi.docs.path`
* `docs/mcp-server.md` — rewritten

### Phase 8: MCP + RAG Foundation

* [x] ~~Phase 8a: MCP Servers~~ ✅
* [x] ~~Phase 8a.2: MCP Resource CRUD + Batch Cascade~~ ✅
* [x] ~~Phase 8a.3: Agent Discovery & Managed Conversations~~ ✅
* [x] ~~Phase 8b: MCP Client + RAG Foundation~~ ✅
* [x] ~~Phase 8c: RAG Foundation~~ ✅

### Phase 8c: RAG Foundation ✅ (commit `f10c0611`)

Config-driven knowledge base retrieval integrated into the LLM pipeline. Knowledge bases are first-class versioned resources with full CRUD, embedding model caching, vector store isolation, and automatic context injection.

| Component               | Files                                                                        | Description                                                         |
| ----------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| **Resource Stack**      | `RagConfiguration`, `IRagStore`, `RagStore`, `IRestRagStore`, `RestRagStore` | Full CRUD at `/ragstore/rags/`, MongoDB collection `rags`           |
| **LLM Config**          | `LlmConfiguration.java`                                                      | `knowledgeBases`, `enableWorkflowRag`, `ragDefaults`, `httpCallRag` |
| **Embedding Factories** | `EmbeddingModelFactory`, `EmbeddingStoreFactory`                             | Cached model/store creation with secret resolution                  |
| **Runtime**             | `RagContextProvider`                                                         | Workflow discovery, retrieval, formatting, audit trace              |
| **Ingestion**           | `RagIngestionService`                                                        | Virtual-thread async ingestion with Caffeine status tracking        |
| **Integration**         | `LlmTask.java`                                                               | RAG context injection before LLM message building                   |

**Tests:** `RestRagStoreTest`, `EmbeddingModelFactoryTest`, `EmbeddingStoreFactoryTest`, `RagContextProviderTest`, updated `LlmTaskTest`.

**Documentation:** `docs/rag.md`

**Sub-phases completed:**

* ✅ Phase 8c-0: httpCall-based RAG — `LlmTask.executeHttpCallRag()`, audit trace, graceful failure
* ✅ Phase 8c-β: pgvector persistent vector store — `EmbeddingStoreFactory.buildPgVector()`, `SecretResolver`, `sanitizeTableName()`
* ✅ Phase 8c-γ: RAG provider expansion — 7 embedding models (openai, azure-openai, ollama, mistral, bedrock, cohere, vertex) + 5 vector stores (in-memory, pgvector, mongodb-atlas, elasticsearch, qdrant) + REST ingestion endpoint (`POST /{id}/ingest`, `GET /{id}/ingestion/{ingestionId}/status`)
* Remaining: Manager UI RAG editor (Phase 13)

### Phase 8a.2: MCP Resource CRUD + Batch Cascade ✅

5 new MCP tools for full resource lifecycle management:

| Tool                   | Description                                                                                        |
| ---------------------- | -------------------------------------------------------------------------------------------------- |
| `update_resource`      | Update any resource config (behavior, langchain, etc.) → returns new version URI                   |
| `create_resource`      | Create a new resource → returns ID + URI                                                           |
| `delete_resource`      | Delete a resource (soft or permanent)                                                              |
| `apply_agent_changes`  | Batch-cascade multiple resource URI changes through package → agent in ONE pass, optional redeploy |
| `list_agent_resources` | Walk agent → packages → extensions to get a complete resource inventory in one call                |

**Key files:**

* `McpAdminTools.java` — 5 new tools, `getRestStore()` shared helper
* `McpToolFilter.java` — whitelist 20 → 27
* `McpAdminToolsCrudTest.java` — 22 new tests
* `docs/mcp-server.md` — updated

### Phase 8a.3: Agent Discovery & Managed Conversations ✅ (commit `4ed7bce8`)

6 new MCP tools for agent discovery and intent-based managed chat:

| Tool                   | Description                                                                         |
| ---------------------- | ----------------------------------------------------------------------------------- |
| `discover_agents`      | Enriched agent list with intent cross-referencing from AgentTriggerConfiguration    |
| `chat_managed`         | Intent-based single-window conversations (one conv per intent+userId, auto-creates) |
| `list_agent_triggers`  | List all intent→agent mappings                                                      |
| `create_agent_trigger` | Create intent-to-agent trigger                                                      |
| `update_agent_trigger` | Update existing trigger                                                             |
| `delete_agent_trigger` | Remove trigger by intent                                                            |

**Key design:** Two-tier conversation model — low-level (`create_conversation` + `talk_to_agent`) for custom apps, managed (`chat_managed`) for single-window chat.

**Key files:**

* `McpConversationTools.java` — `discover_agents` + `chat_managed` + `getOrCreateManagedConversation` helper
* `McpAdminTools.java` — 4 trigger CRUD tools
* `McpToolFilter.java` — whitelist 27 → 33
* `McpConversationToolsTest.java` — 7 new tests
* `McpAdminToolsCrudTest.java` — 7 new tests
* `docs/mcp-server.md` — comprehensive Tool Reference section (parameter tables, response schemas, end-to-end examples)

**Live test results:** All 6 tools tested against running backend — discover\_agents (80 agents, filter works), triggers CRUD (create/update/delete), chat\_managed (conversation auto-created, reused on follow-up).

### Phase 8b: MCP Client + Quarkus 3.32.4 ✅

Agents can now consume external MCP servers as tool providers. Upgraded Quarkus to 3.32.4.

| Component                  | Change                                                                             |
| -------------------------- | ---------------------------------------------------------------------------------- |
| **POM**                    | Added `langchain4j-mcp` 1.12.2-beta22, upgraded Quarkus 3.30.8 → 3.32.4            |
| **McpToolProviderManager** | NEW — `StreamableHttpMcpTransport`, connection caching, vault-ref, graceful errors |
| **AgentOrchestrator**      | MCP tools merged into tool-calling loop with budget/rate-limiting                  |
| **LangChainConfiguration** | Added `mcpServers` + `McpServerConfig` (url, name, transport, apiKey, timeoutMs)   |
| **McpSetupTools**          | `mcpServers` param on `setup_agent` tool                                           |

**Test results:** 1045 tests, 0 failures. `McpToolProviderManagerTest` (8 tests), updated `AgentOrchestratorTest` + `LangchainTaskTest` + `McpSetupToolsTest` (21 calls). Also fixed pre-existing `AgentFactoryTest` failure.

**Key files:**

* `McpToolProviderManager.java` (NEW)
* `McpToolProviderManagerTest.java` (NEW)
* `AgentOrchestrator.java`
* `LangChainConfiguration.java` (`McpServerConfig`)
* `McpSetupTools.java`
* `pom.xml`

### Httpcall Auto-Discovery from Workflow ✅

Agents now auto-discover `httpcall` configurations from their workflow and expose them as LLM tools at runtime. No version-coupled `tools[]` array needed in LLM configuration.

**Key design:** `AgentOrchestrator.discoverHttpCallTools()` traverses agent → workflow → httpcall steps at execution time. Uses direct `IRestAgentStore`/`IRestWorkflowStore` reads (not `ResourceClientLibrary`, which lacks agent/workflow URI mappings).

**Config:** `enableHttpCallTools` defaults to `true` in `LlmConfiguration.Task`. Not a standalone agent-mode trigger — only activates when agent mode is already triggered by tools, builtInTools, or mcpServers.

**Key files:**

* `src/main/java/ai/labs/eddi/modules/llm/impl/AgentOrchestrator.java` — `discoverHttpCallTools()`, `HttpCallToolsResult`
* `src/main/java/ai/labs/eddi/modules/llm/impl/LlmTask.java` — injects stores into `AgentOrchestrator`
* `src/main/java/ai/labs/eddi/modules/llm/model/LlmConfiguration.java` — `enableHttpCallTools` field
* `src/test/java/ai/labs/eddi/modules/llm/impl/AgentOrchestratorTest.java` — 7 new tests (30 total)

See `AGENTS.md` for the full roadmap (Phases 7–14b) and `docs/project-philosophy.md` for the 9 architectural pillars.

### LLM Provider Expansion: 7 → 12 Providers ✅

Expanded EDDI from 7 to 12 model providers for enterprise completeness. 4 new `ILanguageModelBuilder` implementations plus OpenAI `baseUrl` for compatible services.

| Provider           | Builder                           | Auth Pattern                             | Streaming   |
| ------------------ | --------------------------------- | ---------------------------------------- | ----------- |
| **Mistral AI**     | `MistralAiLanguageModelBuilder`   | `apiKey`                                 | ✅           |
| **Azure OpenAI**   | `AzureOpenAiLanguageModelBuilder` | `apiKey` + `endpoint` + `deploymentName` | ✅           |
| **Amazon Bedrock** | `BedrockLanguageModelBuilder`     | AWS credential chain (no apiKey)         | ✅           |
| **Oracle GenAI**   | `OracleGenAiLanguageModelBuilder` | OCI config (`~/.oci/config`)             | ❌ sync-only |

**Downstream integration:**

* `AgentSetupService`: `isLocalLlmProvider` (bedrock, oracle-genai bypass apiKey), `supportsResponseFormat` (mistral, azure-openai), `createLlmConfig` (provider-specific param mapping)
* `McpSetupTools`: `@ToolArg` docs list all 11 provider types
* `LlmModule`: 4 new type keys registered

**API corrections (code review):**

* Bedrock: `temperature()`/`maxTokens()` don't exist on builder → uses `defaultRequestParameters(BedrockChatRequestParameters)`
* Oracle GenAI: package `dev.langchain4j.community.model.oracle.oci.genai` (not `.model.oci.genai`), uses `modelName` (not `modelId`)

**Key files:**

* `src/main/java/ai/labs/eddi/modules/llm/impl/builder/MistralAiLanguageModelBuilder.java` (NEW)
* `src/main/java/ai/labs/eddi/modules/llm/impl/builder/AzureOpenAiLanguageModelBuilder.java` (NEW)
* `src/main/java/ai/labs/eddi/modules/llm/impl/builder/BedrockLanguageModelBuilder.java` (NEW)
* `src/main/java/ai/labs/eddi/modules/llm/impl/builder/OracleGenAiLanguageModelBuilder.java` (NEW)
* `src/main/java/ai/labs/eddi/modules/llm/bootstrap/LlmModule.java`
* `src/main/java/ai/labs/eddi/engine/setup/AgentSetupService.java`
* `src/main/java/ai/labs/eddi/engine/mcp/McpSetupTools.java`
* `src/test/java/ai/labs/eddi/engine/mcp/McpSetupToolsTest.java` — 11 new test cases
* `docs/langchain.md` — all 12 providers documented with config examples
* `docs/changelog.md` — full entry with design decisions

### Platform Remediation: Thread Safety, A2A Hardening, Code Quality & Audit DLQ ✅

Critical architectural fixes from thorough v6 feature review. 12 files modified, 1 new file.

| Change          | Details                                                                                                                       |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Virtual threads | `CascadingModelExecutor` + `GroupConversationService` — replaced `CachedThreadPool`                                           |
| A2A security    | `@Authenticated` POST, circuit breaker, 1MB limit, JSON-RPC validation                                                        |
| Code quality    | `WorkflowTraversal` DRY, `JsonStringEncoder` escaping, `maxToolIterations`, `isRetryableError` HTTP status codes              |
| Observability   | Audit dead-letter: NATS JetStream first (`eddi.deadletter.audit`), file fallback (configurable `eddi.audit.dead-letter-path`) |
| Tests           | 1291 total (1289 pass, 2 pre-existing isolation failures)                                                                     |

### One-Command Install & Onboarding Wizard ✅

New users can set up EDDI with `curl ... | bash` (Linux/macOS/WSL) or download-and-run `install.ps1` (Windows). Interactive 5-step wizard.

| File                               | Description                                                                                                                      |
| ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `install.sh`                       | Bash installer: platform-aware Docker install, DB/Security/Auth/Monitoring/Ports wizard, `eddi` CLI wrapper, Agent Father import |
| `install.ps1`                      | PowerShell installer: `winget` Docker Desktop auto-install, same wizard flow                                                     |
| `docker-compose.postgres-only.yml` | PostgreSQL-only compose (no MongoDB)                                                                                             |
| `docker-compose.auth.yml`          | Keycloak overlay                                                                                                                 |
| `docker-compose.monitoring.yml`    | Grafana + Prometheus overlay (placeholder)                                                                                       |
| `README.md`                        | Quick Start section                                                                                                              |
| `docs/getting-started.md`          | Option 0 — one-command install                                                                                                   |

**Vault security:** Step 2/5 generates a unique, cryptographically random vault master key (or accepts a custom passphrase). The key is stored in `~/.eddi/.env` (chmod 600 / ACL-restricted) and passed to Docker Compose via `--env-file`. All compose files use `${EDDI_VAULT_MASTER_KEY:-}` variable substitution — no hardcoded keys.

**Edge cases handled:** Idempotent re-runs (preserves existing vault key), CTRL+C cleanup, piped stdin (`curl|bash` auto-generates key), disk space warning, input validation, macOS `wc -l` whitespace, Docker auto-install (Linux/Windows), macOS-compatible `sed` (no `grep -oP`).

### Phase 11a: Persistent User Memory ✅

Cross-conversation, agent-scoped fact retention with LLM tools, REST API, MCP management, and background consolidation.

| Component         | Key Files                                                                                                                                                   |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Data Model**    | `UserMemoryEntry.java`, `Property.java` (Visibility enum)                                                                                                   |
| **Unified Store** | `IUserMemoryStore.java`, `MongoUserMemoryStore.java`, `PostgresUserMemoryStore.java`                                                                        |
| **Agent Config**  | `AgentConfiguration.java` (UserMemoryConfig, Guardrails, DreamConfig)                                                                                       |
| **LLM Tool**      | `UserMemoryTool.java` (`@Vetoed`, 4 tools: remember/recall/search/forget)                                                                                   |
| **REST API**      | `IRestUserMemoryStore.java`, `RestUserMemoryStore.java` (9 endpoints + validation)                                                                          |
| **MCP Tools**     | `McpMemoryTools.java` (8 tools, GDPR-compliant)                                                                                                             |
| **Dream**         | `DreamService.java` (stale pruning, contradiction detection, LLM-driven summarization, Micrometer metrics)                                                  |
| **Integration**   | `AgentOrchestrator.java` (groupId extraction), `GroupConversationService.java` (groupId context)                                                            |
| **Docs**          | `docs/user-memory.md`, `docs/changelog.md`, `docs/SUMMARY.md`                                                                                               |
| **Tests**         | 107 new: `UserMemoryToolTest` (16), `DreamServiceTest` (51), `UserMemoryEntryTest` (22), `RestUserMemoryStoreTest` (15), `SummarizationServiceTest` (3 new) |

**Total tests:** 1406 (all pass). **Last commit:** Phase 11a code review fixes.

### Properties Consolidation: `IPropertiesStore` → `IUserMemoryStore` ✅

Eliminated the legacy `properties` collection and unified all user-scoped persistent storage into `usermemories`. Removes a redundant storage layer.

| Change                | Details                                                                                     |
| --------------------- | ------------------------------------------------------------------------------------------- |
| **Deleted**           | `IPropertiesStore.java`, `PropertiesStore.java` (Mongo), `PostgresPropertiesStore.java`     |
| **Renamed**           | `enableUserMemory` → `enableMemoryTools` (gates advanced tools only, not basic persistence) |
| **Conversation.java** | Consolidated dual load/store into single unified flow via `IUserMemoryStore`                |
| **REST preserved**    | `RestPropertiesStore` delegates to `IUserMemoryStore` flat property methods                 |
| **Migration**         | `PropertiesMigrationService` (MongoDB startup migration, `@IfBuildProfile("!postgres")`)    |

**Code review fixes (commit `7997da96`):**

* Bug: Removed dead `DELETE FROM properties` in Postgres GDPR delete
* Bug: Guarded `PropertiesMigrationService` with `@IfBuildProfile("!postgres")` (was `@DefaultBean`)
* Fix: Added `List` type handling to `Conversation.entryToProperty()`
* Fix: `IPropertiesHandler` javadoc consistency
* Cleanup: Moved redundant `set(FIELD_VISIBILITY)` to `setOnInsert` in MongoDB merge

**Docs updated:** `docs/user-memory.md`, `docs/changelog.md`

### Phase 11b: Token-Aware Conversation Window (Strategy 1) ✅

Config-driven token-budget windowing with anchored opening steps, replacing fixed step-count limits for LLM context management.

| Component          | Key Files                                                                                                                                          |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Config**         | `LlmConfiguration.java` (`maxContextTokens`, `anchorFirstSteps` fields)                                                                            |
| **Token Counting** | `TokenCounterFactory.java` (OpenAI tiktoken + approximate chars/4 fallback)                                                                        |
| **Window Builder** | `ConversationHistoryBuilder.java` (`buildTokenAwareMessages()` — anchor + gap marker + recent)                                                     |
| **Integration**    | `LlmTask.java` (branch: token-aware vs step-count based on config)                                                                                 |
| **Docs**           | `docs/langchain.md` (new "Conversation Window Management" section)                                                                                 |
| **Tests**          | `TokenCounterFactoryTest.java` (20 tests), `ConversationHistoryBuilderTest.java` (+16 token-aware tests), `LlmTaskTest.java` (updated constructor) |

**Design:** `maxContextTokens=-1` (default) preserves existing step-count behavior. When set > 0, first N steps are anchored, remaining budget filled from most recent backward, gap marker inserted for omitted messages.

**Code review fixes:** Model name resolution (fallback chain: modelName→model→modelId→deploymentName), anchor budget overflow warning + `Math.max(0, ...)`, gap marker shows count not indices, removed dead code, instance-level cache. 9 edge case tests added (empty conversation, anchor clamping, budget overflow, exact boundary, etc.).

**Total tests:** 1459 (all pass). **Last commit:** Phase 11b code review fixes.

### Phase 11b-S2: Rolling Summary + Conversation Recall Tool ✅

Config-driven rolling summary that compresses older conversation turns into an incremental summary, injected as a context prefix. Includes a built-in LLM tool for drill-back into summarized turns.

| Component                  | Key Files                                                                                                   |
| -------------------------- | ----------------------------------------------------------------------------------------------------------- |
| **SummarizationService**   | `SummarizationService.java` — stateless LLM summarization via ChatModelRegistry                             |
| **ConversationSummarizer** | `ConversationSummarizer.java` — incremental engine, self-correcting, conversation-property storage          |
| **ConversationRecallTool** | `ConversationRecallTool.java` — built-in `@Vetoed` tool for LLM drill-back (natural language range parsing) |
| **Config**                 | `LlmConfiguration.java` — `ConversationSummaryConfig` inner class (provider, model, window, recall limit)   |
| **History Builder**        | `ConversationHistoryBuilder.java` — summary-aware `buildMessages()` / `buildTokenAwareMessages()`           |
| **Orchestrator**           | `AgentOrchestrator.java` — auto-registers ConversationRecallTool when summary is active                     |
| **LlmTask**                | `LlmTask.java` — summary prefix injection before history build + post-response summarization trigger        |
| **Tests**                  | `SummarizationServiceTest` (5), `ConversationSummarizerTest` (11), `ConversationRecallToolTest` (12)        |

**Design:** Summaries stored as conversation-scoped properties (`conversation:running_summary`, `conversation:summary_through_step`) for O(1) retrieval. Synchronous trigger after LLM response. Self-correcting: if turn N fails, turn N+1 catches up. Defaults: `claude-sonnet-4-6` provider, `20` max recall turns, `5` recent window steps.

**Total tests:** 1471 (all pass).

## Important Rules

* All work on **`feature/version-6.0.0`** branch (never `main`)
* Read `AGENTS.md` for development order and guidelines
* Read `docs/project-philosophy.md` for architectural pillars
* Read `docs/v6-planning/` for architecture analysis, changelog, and business logic analysis
* Commit often with conventional commits
* Run `.\mvnw test` before committing
* Suggest a new conversation when a phase or major item is completed
