From 8aebd3e0d7a766c97731bdb34501e7d549ad8b47 Mon Sep 17 00:00:00 2001 From: ngirchev Date: Fri, 1 May 2026 15:11:50 +0300 Subject: [PATCH 1/7] Clean up --- ...e-hygiene-dependency-analyze-2026-04-30.md | 165 +++++++ .../workflow/subagent_usage_preference.md | 12 + .serena/project.yml | 77 ++- AGENTS.md | 5 +- TODO.md | 60 ++- docs/team/archunit-rules.md | 441 ++++++++++++++++++ opendaimon-app/pom.xml | 201 ++++++-- .../opendaimon/arch/ArchitectureTest.java | 167 +++++++ ...SpringAIGatewayStreamingRealContextIT.java | 44 +- opendaimon-common/pom.xml | 180 +++++-- .../persistence/AgentExecutionRepository.java | 2 - .../repository/AssistantRoleRepository.java | 2 - .../repository/BugreportRepository.java | 2 - .../ConversationThreadRepository.java | 2 - .../OpenDaimonMessageRepository.java | 2 - .../repository/UserRecentModelRepository.java | 2 - .../common/repository/UserRepository.java | 2 - .../service/ConversationThreadService.java | 20 + .../service/OpenDaimonMessageService.java | 13 + .../config/BulkHeadPropertiesTest.java | 14 + .../common/arch/CommonArchitectureTest.java | 195 ++++++++ opendaimon-gateway-mock/pom.xml | 69 ++- opendaimon-rest/pom.xml | 215 ++++++++- .../AdminConversationRepository.java | 2 - .../rest/repository/AdminUserRepository.java | 2 - .../rest/repository/RestUserRepository.java | 2 - .../rest/service/RestUserService.java | 31 +- .../rest/arch/RestArchitectureTest.java | 185 ++++++++ .../SessionControllerContractTest.java | 47 +- .../handler/RestChatHandlerSupportTest.java | 9 +- opendaimon-spring-ai/pom.xml | 249 ++++++++-- .../springai/config/SpringAIAutoConfig.java | 12 +- .../memory/SummarizingChatMemory.java | 28 +- .../memory/SummarizingChatMemoryTest.java | 62 +-- opendaimon-telegram/pom.xml | 176 ++++++- .../impl/HistoryTelegramCommandHandler.java | 20 +- .../impl/NewThreadTelegramCommandHandler.java | 11 +- .../impl/ThreadsTelegramCommandHandler.java | 10 +- .../config/TelegramCommandHandlerConfig.java | 13 +- .../repository/TelegramGroupRepository.java | 2 - .../repository/TelegramUserRepository.java | 2 - .../TelegramUserSessionRepository.java | 2 - .../TelegramWhitelistRepository.java | 2 - ...elegramTextCommandHandlerProviderTest.java | 3 - .../HistoryTelegramCommandHandlerTest.java | 22 +- .../NewThreadTelegramCommandHandlerTest.java | 20 +- .../ThreadsTelegramCommandHandlerTest.java | 14 +- opendaimon-ui/pom.xml | 77 ++- pom.xml | 285 +++++++++-- 49 files changed, 2707 insertions(+), 473 deletions(-) create mode 100644 .serena/memories/handoff/module-hygiene-dependency-analyze-2026-04-30.md create mode 100644 .serena/memories/workflow/subagent_usage_preference.md create mode 100644 docs/team/archunit-rules.md create mode 100644 opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java create mode 100644 opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/common/arch/CommonArchitectureTest.java create mode 100644 opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/arch/RestArchitectureTest.java diff --git a/.serena/memories/handoff/module-hygiene-dependency-analyze-2026-04-30.md b/.serena/memories/handoff/module-hygiene-dependency-analyze-2026-04-30.md new file mode 100644 index 00000000..92a7971c --- /dev/null +++ b/.serena/memories/handoff/module-hygiene-dependency-analyze-2026-04-30.md @@ -0,0 +1,165 @@ +# Handoff: module hygiene / dependency analyze / ArchUnit + +Date: 2026-04-30 +Project: open-daimon + +## User request +Implement Maven Central readiness plan: +- minimal dependency declarations per module (`declare what you use`) +- reactor-wide `dependency:analyze` +- wire `maven-dependency-plugin:analyze-only` into `verify` with `failOnWarning=true` +- add ArchUnit boundary/layer rules +- add Maven Enforcer rules: dependency convergence, upper bounds, ban commons-logging, ban Spring Boot starters in non-app modules. + +User then asked to split remaining work by module and persist state for a new session. + +## Important project constraints +- Do not revert unrelated user/AI dirty changes. +- Public APIs matter. Avoid public type/method removals/renames unless explicitly approved. +- Modules are published/consumed independently; each module must declare directly-used libraries even if transitively available. +- No `@Service`, `@Component`, `@Repository` in main sources; explicit `@Bean` config only. +- Code/docs in repo must be English. + +## Dirty state known before this work +Unrelated/generated files existed and should not be reverted unless user asks: +- `.serena/project.yml` modified +- docs/team files added +- various repository interfaces had `@Repository` removed by prior work +- some POMs were already partially edited + +## Completed changes +### Root `pom.xml` +- Spring Boot aligned to `3.5.13`. +- Removed explicit Spring Framework BOM override. +- Updated several managed versions: + - `postgresql.version=42.7.10` + - `flyway.version=11.7.2` + - `flyway-database-postgresql.version=11.7.2` + - `jakarta-xml-bind.version=4.0.4` + - `lombok.version=1.18.44` + - `testcontainers.version=1.21.4` + - `h2.version=2.3.232` + - `maven-dependency-plugin.version=3.8.1` + - `maven-enforcer-plugin.version=3.6.2` + - `archunit.version=1.4.2` +- Added commons-logging exclusions to managed `httpclient` and `pdfbox`. +- Added pluginManagement for `maven-dependency-plugin:analyze-only` bound to `verify` with `failOnWarning=true`, `ignoreNonCompile=true`, `outputXML=true`. +- Added pluginManagement for `maven-enforcer-plugin` bound to `verify` with `dependencyConvergence`, `requireUpperBoundDeps`, and transitive banned `commons-logging:commons-logging`. +- Activated dependency/enforcer plugins in root ``. + +### Module POMs +- Copied dependency-cleanup baseline POMs from `../open-daimon-2` into current repo before patching further. +- Added module-local enforcer config banning transitive `org.springframework.boot:spring-boot-starter*` in non-app modules: + - `opendaimon-common` + - `opendaimon-spring-ai` + - `opendaimon-rest` + - `opendaimon-telegram` + - `opendaimon-ui` + - `opendaimon-gateway-mock` +- `opendaimon-app/pom.xml`: added `com.tngtech.archunit:archunit-junit5` test dependency and analyzer ignores for ArchUnit. +- `opendaimon-spring-ai/pom.xml`: replaced Spring AI starter runtime deps with non-starter autoconfigure deps: + - `spring-ai-autoconfigure-model-chat-memory` + - `spring-ai-autoconfigure-model-chat-memory-repository-jdbc` +- `opendaimon-common/pom.xml`: removed unused main deps reported by analyzer: + - `reactor-netty-http` + - `hibernate-validator` + - `postgresql` + - `micrometer-registry-prometheus` + - `resilience4j-spring-boot2` + +### Code boundary changes +Moved direct repository access out of delivery/service clients and behind services: +- `ConversationThreadService` gained: + - `findThreads(ThreadScopeKind scopeKind, Long scopeId)` + - `closeCurrentThread(ThreadScopeKind scopeKind, Long scopeId)` + - existing `findByThreadKey` marked read-only transactional +- `OpenDaimonMessageService` gained: + - `findByThreadOrderBySequenceNumberAsc(ConversationThread thread)` + - `findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(ConversationThread thread, Integer minSequenceNumber)` +- `HistoryTelegramCommandHandler` uses `ConversationThreadService` and `OpenDaimonMessageService`. +- `ThreadsTelegramCommandHandler` uses `ConversationThreadService.findThreads`. +- `NewThreadTelegramCommandHandler` uses `ConversationThreadService.closeCurrentThread`. +- `SummarizingChatMemory` uses `ConversationThreadService` and `OpenDaimonMessageService`. +- `TelegramCommandHandlerConfig` and `SpringAIAutoConfig` wiring updated accordingly. + +### Tests partially updated +- `SummarizingChatMemoryTest` updated from repository mocks to service mocks. +- Telegram handler tests were patched but not re-verified after patch due user interrupt: + - `ThreadsTelegramCommandHandlerTest`: removed repository mock and uses `threadService.findThreads`. + - `HistoryTelegramCommandHandlerTest`: uses `ConversationThreadService` and `OpenDaimonMessageService` mocks. + - `NewThreadTelegramCommandHandlerTest`: removed repository mock and verifies `closeCurrentThread`. + +### ArchUnit +- Deleted old frozen `ArchitectureTest` and frozen store files: + - `opendaimon-app/src/test/resources/archunit.properties` + - files under `opendaimon-app/archunit_store/` +- Added new `opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java` with rules: + - no `@Service`, `@Component`, `@Repository` in common/springai/telegram/rest/ui main packages + - no cyclic library module dependencies + - telegram must not depend on rest + - rest must not depend on telegram + - only app/root package may depend on multiple delivery channels + - repository layer may only be accessed by service/config layers + +## Verification completed before interrupt +- `./mvnw -pl opendaimon-app -am clean compile -DskipTests` passed. +- `./mvnw dependency:analyze -DskipTests` first failed on `SummarizingChatMemoryTest`; fixed. +- Re-run of `dependency:analyze -DskipTests` progressed and found module warnings before telegram test compile failure: + - `opendaimon-common`: no dependency problems at that point. + - `opendaimon-spring-ai`: unused declared warnings for: + - `org.springframework.ai:spring-ai-autoconfigure-model-chat-memory` runtime + - `org.springframework.ai:spring-ai-autoconfigure-model-chat-memory-repository-jdbc` runtime + - `com.h2database:h2` test + - `opendaimon-rest`: warnings: + - unused declared `org.hamcrest:hamcrest:test` + - non-test scoped test-only `com.fasterxml.jackson.core:jackson-core:compile` + - non-test scoped test-only `org.springframework:spring-beans:compile` + - `opendaimon-telegram`: test compile failed because handler tests still used old constructors; patched afterwards, but not re-run. +- Targeted command `./mvnw -pl opendaimon-telegram -am test -DskipITs -DskipIT -DfailIfNoTests=false` failed in upstream `opendaimon-common` tests because `hibernate-validator` had been removed and Spring configuration properties validation needs a provider at test runtime. + +## Current blocker at interrupt +`opendaimon-common` tests fail with: +`jakarta.validation.NoProviderFoundException: Unable to create a Configuration, because no Jakarta Bean Validation provider could be found.` +This came from `BulkHeadPropertiesTest` loading Spring context. Likely fix: add `org.hibernate.validator:hibernate-validator` back as test-scoped dependency in `opendaimon-common`, not compile scoped, unless production module needs to provide validation provider to downstream consumers. Verify analyzer afterwards. + +## Suggested module-by-module continuation plan +1. `opendaimon-common` + - Add `hibernate-validator` as test dependency or otherwise provide validation provider only for tests. + - Run: `./mvnw -pl opendaimon-common test dependency:analyze -DskipITs -DskipIT`. + - Ensure no analyzer warnings. + +2. `opendaimon-spring-ai` + - Decide on analyzer handling for runtime Spring AI autoconfig glue and H2. + - If runtime autoconfig jars are intentionally present for Boot auto-configuration, add module-local `ignoredUnusedDeclaredDependencies` with precise comments. + - Remove H2 if genuinely unused, or ignore if Boot test infra loads it implicitly. + - Review `jakarta.persistence-api`: currently test scoped and compile has warnings about missing enum constants during app compile; may need compile scope if main bytecode references persistence types indirectly. + - Run: `./mvnw -pl opendaimon-spring-ai -am clean compile test dependency:analyze -DskipITs -DskipIT`. + +3. `opendaimon-rest` + - Remove `org.hamcrest:hamcrest` if no direct imports. + - For `spring-beans` and `jackson-core`, either move to test scope if truly test-only, or add `ignoredNonTestScopedDependencies` if they must remain main-runtime deps. Existing comment incorrectly only handles unused-declared category. + - Run: `./mvnw -pl opendaimon-rest -am clean compile test dependency:analyze -DskipITs -DskipIT`. + +4. `opendaimon-telegram` + - Re-run tests after patched constructors. + - Confirm Caffeine is declared directly because `TelegramChatPacerImpl` imports it. + - Run: `./mvnw -pl opendaimon-telegram -am clean compile test dependency:analyze -DskipITs -DskipIT`. + +5. `opendaimon-ui` and `opendaimon-gateway-mock` + - Run module analyzer/enforcer separately and fix only local warnings. + +6. `opendaimon-app` ArchUnit + - Run: `./mvnw -pl opendaimon-app -am test -Dtest=ArchitectureTest -Dsurefire.failIfNoSpecifiedTests=false`. + - Fix real violations, do not restore freeze store. + +7. Reactor final checks + - `./mvnw clean compile` + - `./mvnw dependency:analyze -DskipTests` + - targeted ArchUnit + - `./mvnw clean verify` + +## Notes for next session +- Do not keep editing globally. Finish one module at a time and verify that module before moving on. +- Watch Maven Enforcer merge behavior: module-local banned starter config may override root rules unless Maven merges as expected. Confirm with `clean verify`. +- The banned starter pattern `org.springframework.boot:spring-boot-starter*` may need to be split into `spring-boot-starter` and `spring-boot-starter-*` if enforcer does not match as intended. +- If Maven needs network and sandbox blocks it, rerun exact command with escalation per Codex instructions. \ No newline at end of file diff --git a/.serena/memories/workflow/subagent_usage_preference.md b/.serena/memories/workflow/subagent_usage_preference.md new file mode 100644 index 00000000..bbe35c2e --- /dev/null +++ b/.serena/memories/workflow/subagent_usage_preference.md @@ -0,0 +1,12 @@ +# Subagent Usage Preference + +User asked to use subagents autonomously only for larger work, especially when many modules are involved, to save main context. + +Apply this rule conservatively: +- Do not spawn subagents for small, single-file, or straightforward tasks. +- Consider subagents for large multi-module changes, broad investigations, parallel verification, or independent review tracks. +- Keep delegated tasks concrete and bounded, with disjoint responsibilities where code edits are involved. +- Continue to do the immediate blocking work locally; delegate only side work that can run in parallel. +- Summarize subagent results back into the main thread instead of carrying all raw context forward. + +This preference does not override Codex/developer constraints: only use subagents when the user has authorized delegation/subagent use, and avoid unnecessary delegation. \ No newline at end of file diff --git a/.serena/project.yml b/.serena/project.yml index 99b3bd60..7d9c2a11 100644 --- a/.serena/project.yml +++ b/.serena/project.yml @@ -3,15 +3,18 @@ project_name: "open-daimon" # list of languages for which language servers are started; choose from: -# al bash clojure cpp csharp -# csharp_omnisharp dart elixir elm erlang -# fortran fsharp go groovy haskell -# java julia kotlin lua markdown -# matlab nix pascal perl php -# php_phpactor powershell python python_jedi r -# rego ruby ruby_solargraph rust scala -# swift terraform toml typescript typescript_vts -# vue yaml zig +# al ansible bash clojure cpp +# cpp_ccls crystal csharp csharp_omnisharp dart +# elixir elm erlang fortran fsharp +# go groovy haskell haxe hlsl +# java json julia kotlin lean4 +# lua luau markdown matlab msl +# nix ocaml pascal perl php +# php_phpactor powershell python python_jedi python_ty +# r rego ruby ruby_solargraph rust +# scala solidity swift systemverilog terraform +# toml typescript typescript_vts vue yaml +# zig # (This list may be outdated. For the current list, see values of Language enum here: # https://github.com/oraios/serena/blob/main/src/solidlsp/ls_config.py # For some languages, there are alternative language servers, e.g. csharp_omnisharp, ruby_solargraph.) @@ -65,53 +68,17 @@ read_only: false # list of tool names to exclude. # This extends the existing exclusions (e.g. from the global configuration) -# -# Below is the complete list of tools for convenience. -# To make sure you have the latest list of tools, and to view their descriptions, -# execute `uv run scripts/print_tool_overview.py`. -# -# * `activate_project`: Activates a project by name. -# * `check_onboarding_performed`: Checks whether project onboarding was already performed. -# * `create_text_file`: Creates/overwrites a file in the project directory. -# * `delete_lines`: Deletes a range of lines within a file. -# * `delete_memory`: Deletes a memory from Serena's project-specific memory store. -# * `execute_shell_command`: Executes a shell command. -# * `find_referencing_code_snippets`: Finds code snippets in which the symbol at the given location is referenced. -# * `find_referencing_symbols`: Finds symbols that reference the symbol at the given location (optionally filtered by type). -# * `find_symbol`: Performs a global (or local) search for symbols with/containing a given name/substring (optionally filtered by type). -# * `get_current_config`: Prints the current configuration of the agent, including the active and available projects, tools, contexts, and modes. -# * `get_symbols_overview`: Gets an overview of the top-level symbols defined in a given file. -# * `initial_instructions`: Gets the initial instructions for the current project. -# Should only be used in settings where the system prompt cannot be set, -# e.g. in clients you have no control over, like Claude Desktop. -# * `insert_after_symbol`: Inserts content after the end of the definition of a given symbol. -# * `insert_at_line`: Inserts content at a given line in a file. -# * `insert_before_symbol`: Inserts content before the beginning of the definition of a given symbol. -# * `list_dir`: Lists files and directories in the given directory (optionally with recursion). -# * `list_memories`: Lists memories in Serena's project-specific memory store. -# * `onboarding`: Performs onboarding (identifying the project structure and essential tasks, e.g. for testing or building). -# * `prepare_for_new_conversation`: Provides instructions for preparing for a new conversation (in order to continue with the necessary context). -# * `read_file`: Reads a file within the project directory. -# * `read_memory`: Reads the memory with the given name from Serena's project-specific memory store. -# * `remove_project`: Removes a project from the Serena configuration. -# * `replace_lines`: Replaces a range of lines within a file with new content. -# * `replace_symbol_body`: Replaces the full definition of a symbol. -# * `restart_language_server`: Restarts the language server, may be necessary when edits not through Serena happen. -# * `search_for_pattern`: Performs a search for a pattern in the project. -# * `summarize_changes`: Provides instructions for summarizing the changes made to the codebase. -# * `switch_modes`: Activates modes by providing a list of their names -# * `think_about_collected_information`: Thinking tool for pondering the completeness of collected information. -# * `think_about_task_adherence`: Thinking tool for determining whether the agent is still on track with the current task. -# * `think_about_whether_you_are_done`: Thinking tool for determining whether the task is truly completed. -# * `write_memory`: Writes a named memory (for future reference) to Serena's project-specific memory store. +# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html excluded_tools: [] # list of tools to include that would otherwise be disabled (particularly optional tools that are disabled by default). # This extends the existing inclusions (e.g. from the global configuration). +# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html included_optional_tools: [] # fixed set of tools to use as the base tool set (if non-empty), replacing Serena's default set of tools. # This cannot be combined with non-empty excluded_tools or included_optional_tools. +# Find the list of tools here: https://oraios.github.io/serena/01-about/035_tools.html fixed_tools: [] # list of mode names to that are always to be included in the set of active modes @@ -122,11 +89,14 @@ fixed_tools: [] # Set this to a list of mode names to always include the respective modes for this project. base_modes: -# list of mode names that are to be activated by default. -# The full set of modes to be activated is base_modes + default_modes. -# If the setting is undefined, the default_modes from the global configuration (serena_config.yml) apply. +# list of mode names that are to be activated by default, overriding the setting in the global configuration. +# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. +# If the setting is undefined/empty, the default_modes from the global configuration (serena_config.yml) apply. # Otherwise, this overrides the setting from the global configuration (serena_config.yml). +# Therefore, you can set this to [] if you do not want the default modes defined in the global config to apply +# for this project. # This setting can, in turn, be overridden by CLI parameters (--mode). +# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes default_modes: # initial prompt for the project. It will always be given to the LLM upon activating the project @@ -150,3 +120,8 @@ read_only_memory_patterns: [] # Extends the list from the global configuration, merging the two lists. # Example: ["_archive/.*", "_episodes/.*"] ignored_memory_patterns: [] + +# list of mode names to be activated additionally for this project, e.g. ["query-projects"] +# The full set of modes to be activated is base_modes (from global config) + default_modes + added_modes. +# See https://oraios.github.io/serena/02-usage/050_configuration.html#modes +added_modes: diff --git a/AGENTS.md b/AGENTS.md index b2d975c3..0a6af7f3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -29,10 +29,13 @@ Consequences for any change touching `pom.xml`, public types, or shared APIs: ### MCP tools for information lookup -- Two MCP servers are available and should be used for information lookup when relevant: +- MCP servers are available and should be used for information lookup when relevant: - `Serena` — codebase navigation, symbol search, and project-aware exploration. + - `JetBrains` — IDE-indexed code search/navigation, symbol documentation, rename refactoring, open-editor context, and inspections. - `Context7` — library/framework documentation lookup and API usage search. - Prefer these MCP tools first for discovery and verification before broader ad-hoc searching. +- Prefer JetBrains MCP for Java refactoring and IDE-backed checks: use it before text-only replacement for renames, before broad shell search when IDE indexing is likely more precise, and for targeted file diagnostics after edits. +- Prefer Context7 for Spring AI, OpenAI API, MCP SDK/transport, Maven plugin, and dependency API questions before answering or implementing from memory. ### Documentation maintenance diff --git a/TODO.md b/TODO.md index 1d00d386..e527ac3b 100644 --- a/TODO.md +++ b/TODO.md @@ -52,8 +52,66 @@ - [ ] Minimal dependency: `opendaimon-common` + `opendaimon-spring-ai` - [ ] **Module hygiene & ArchUnit** — enforce clean module boundaries before publishing to Maven Central (see `AGENTS.md` § Project Nature) - [ ] **`./mvnw dependency:analyze` reactor-wide** — fix every `Used undeclared dependencies` and `Unused declared dependencies` finding, then wire `maven-dependency-plugin:analyze-only` into the `verify` phase with `failOnWarning=true` so future undeclared / unused deps break CI. First known cases: `opendaimon-telegram` uses Caffeine in `TelegramChatPacerImpl` without declaring it (transitively via `opendaimon-common`); `opendaimon-spring-ai` re-declares Caffeine that already comes through `opendaimon-common` — keep the declaration (per "declare what you use") and verify nothing else falls in the same trap. - - [ ] **ArchUnit test module** — inter-module boundary rules (`opendaimon-telegram` ↛ `opendaimon-rest`, `opendaimon-rest` ↛ `opendaimon-telegram`, only `opendaimon-app` may depend on multiple delivery-channel modules), per-module layering (`config` → `service` → `repository`, never the reverse), and a "no `@Service`/`@Component`/`@Repository` outside test sources" guard that codifies the explicit-`@Bean` rule from `AGENTS.md` § Spring Bean Configuration. + - [ ] **ArchUnit test module** — inter-module boundary rules (`opendaimon-telegram` ↛ `opendaimon-rest`, `opendaimon-rest` ↛ `opendaimon-telegram`, only `opendaimon-app` may depend on multiple delivery-channel modules), per-module layering (`config` → `service` → `repository`, never the reverse), and a guard that forbids `@Service` / `@Component` beans plus concrete `@Repository` classes outside test sources while allowing Spring Data repository interfaces. - [ ] **`maven-enforcer-plugin` rules** — `dependencyConvergence` (single resolved version per transitive dep), `requireUpperBoundDeps`, `bannedDependencies` (no `commons-logging`, no `*-spring-boot-starter` in non-`opendaimon-app` modules to keep delivery-channel modules embeddable in third-party Spring Boot apps). + - [ ] **Continuation checkpoint: module hygiene / dependency analyze / ArchUnit** + - [x] Root Maven hygiene baseline + - Spring Boot aligned to `3.5.13`. + - Removed explicit Spring Framework BOM override. + - Added `maven-dependency-plugin:analyze-only` in `verify` with `failOnWarning=true`. + - Added root `maven-enforcer-plugin` in `verify` with `dependencyConvergence`, `requireUpperBoundDeps`, and transitive `commons-logging:commons-logging` ban. + - Added managed `archunit.version=1.4.2` and `maven-enforcer-plugin.version=3.6.2`. + - [x] Non-app starter ban baseline + - Added module-local enforcer config banning transitive `org.springframework.boot:spring-boot-starter*` in `opendaimon-common`, `opendaimon-spring-ai`, `opendaimon-rest`, `opendaimon-telegram`, `opendaimon-ui`, and `opendaimon-gateway-mock`. + - Follow-up verification still needed: confirm the module-local enforcer config merges with root convergence / upper-bound / commons-logging rules instead of overriding them. + - [x] ArchUnit baseline + - Added `opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java`. + - Rules cover no `@Service` / `@Component` beans and no concrete `@Repository` classes in main module packages, no library-module cycles, telegram ↛ rest, rest ↛ telegram, only app/root may depend on multiple delivery channels, and repository access only from `service` / `config`. + - Removed frozen ArchUnit store/config files; do not restore freeze mode. + - [x] `opendaimon-common` ArchUnit hardening + - Added `opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/common/arch/CommonArchitectureTest.java`. + - Rules cover no `@Service` / `@Component` beans, no concrete `@Repository` classes, no delivery controllers in common/bulkhead, no downstream module dependencies, no common runtime slice cycles, repository interfaces, repository access boundaries, and config/property package conventions. + - Verified with `./mvnw clean compile -pl opendaimon-common`, `./mvnw test -pl opendaimon-common -Dtest=CommonArchitectureTest`, and `./mvnw test -pl opendaimon-common` (283 tests, 0 failures/errors, 2 skipped). + - [x] Repository boundary cleanup in production code + - `ConversationThreadService` gained `findThreads(...)`, `closeCurrentThread(...)`, and read-only `findByThreadKey(...)`. + - `OpenDaimonMessageService` gained read methods used by Telegram and Spring AI memory code. + - `HistoryTelegramCommandHandler`, `ThreadsTelegramCommandHandler`, `NewThreadTelegramCommandHandler`, and `SummarizingChatMemory` were moved off direct repository access. + - `TelegramCommandHandlerConfig` and `SpringAIAutoConfig` constructor wiring was updated for the service-layer boundary. + - [x] Tests updated so far + - `SummarizingChatMemoryTest` uses service mocks instead of repository mocks. + - `HistoryTelegramCommandHandlerTest`, `ThreadsTelegramCommandHandlerTest`, and `NewThreadTelegramCommandHandlerTest` were patched for the new constructors/service methods, but still need a clean re-run. + - [x] `opendaimon-common` module cleanup + - `org.hibernate.validator:hibernate-validator` is declared as a test-scoped validation provider for `BulkHeadPropertiesTest`; it is not exported as compile API. + - ArchUnit test dependencies are declared as direct test dependencies (`archunit`, `archunit-junit5-api`) plus the JUnit Platform runtime engine (`archunit-junit5-engine`) with a targeted analyzer ignore. + - Verified with `./mvnw -pl opendaimon-common test dependency:analyze -DskipITs -DskipIT`: 283 tests, 0 failures/errors, 2 skipped; dependency analyzer reports `No dependency problems found`. + - [ ] `opendaimon-spring-ai` module cleanup + - Analyzer warnings observed: + - unused declared `org.springframework.ai:spring-ai-autoconfigure-model-chat-memory:runtime` + - unused declared `org.springframework.ai:spring-ai-autoconfigure-model-chat-memory-repository-jdbc:runtime` + - unused declared `com.h2database:h2:test` + - Decide whether runtime autoconfig glue should be precisely ignored with comments or removed. + - Review `jakarta.persistence-api`: it is currently test-scoped, while compile showed missing enum-constant warnings in app compile; move to compile only if main bytecode really needs it. + - Verify with `./mvnw -pl opendaimon-spring-ai -am clean compile test dependency:analyze -DskipITs -DskipIT`. + - [x] `opendaimon-rest` module cleanup + - Added REST-local `RestArchitectureTest` with layer, explicit-configuration, repository, DTO/model, and service/delivery boundary rules. + - Added REST ArchUnit test dependencies and targeted analyzer ignore for the JUnit Platform engine. + - Kept `org.hamcrest:hamcrest:test` because `SessionControllerContractTest` imports Hamcrest matchers directly. + - Resolved previous `jackson-core` / `spring-beans` analyzer warnings through direct dependency cleanup. + - Verified with `./mvnw -pl opendaimon-rest -am clean compile -DskipTests`, `./mvnw -pl opendaimon-rest -am test -Dtest=RestArchitectureTest -Dsurefire.failIfNoSpecifiedTests=false -DskipITs -DskipIT`, `./mvnw -pl opendaimon-rest -am dependency:analyze -DskipTests`, and `./mvnw -pl opendaimon-rest -am test -DskipITs -DskipIT`. + - [ ] `opendaimon-telegram` module cleanup + - Re-run tests after handler-test constructor patches. + - Confirm `com.github.ben-manes.caffeine:caffeine` is declared directly because `TelegramChatPacerImpl` imports it. + - Verify with `./mvnw -pl opendaimon-telegram -am clean compile test dependency:analyze -DskipITs -DskipIT`. + - [x] `opendaimon-ui` and `opendaimon-gateway-mock` module cleanup + - Run analyzer/enforcer per module and fix only local POM warnings. + - [ ] `opendaimon-app` ArchUnit verification + - Run `./mvnw -pl opendaimon-app -am test -Dtest=ArchitectureTest -Dsurefire.failIfNoSpecifiedTests=false`. + - Fix real boundary/layer violations in code; do not reintroduce frozen ArchUnit rules. + - [ ] Final reactor verification + - Run `./mvnw clean compile`. + - Run `./mvnw dependency:analyze -DskipTests`. + - Run targeted `ArchitectureTest`. + - Run `./mvnw clean verify`. ## Agent Framework Pivot diff --git a/docs/team/archunit-rules.md b/docs/team/archunit-rules.md new file mode 100644 index 00000000..f0c80fe1 --- /dev/null +++ b/docs/team/archunit-rules.md @@ -0,0 +1,441 @@ +--- +slug: archunit-rules +title: "ArchUnit Architecture Rules" +owner: ngirchev +created: 2026-04-28 +status: done +base_branch: fsm +--- + +## §0 One-Line Summary + +Introduce ArchUnit-based tests enforcing the architectural invariants already documented in AGENTS.md. Minimum-rule first pass: no @Service/@Component (Spring stereotypes), no cyclic dependencies between opendaimon-* modules, services live in .service packages, implementations carry the Impl suffix. This is session 1 of 3 — followed later by /team dependency-cleanup and /team opendaimon-spring-boot-starter. + +## §1 Problem Statement + +The architectural invariants documented in `AGENTS.md` (Project Style Guide) are enforced today only by reviewer effort: + +- Library modules export beans through `@Bean` methods in `@Configuration` classes (no `@Service`/`@Component`) so the future `opendaimon-spring-boot-starter` can let downstream consumers override them via `@ConditionalOnMissingBean` and property toggles. +- The dependency graph between library modules forms a DAG — cycles would break Maven build ordering and downstream classpaths. + +Before publishing the public starter (a future `/team` session), we want executable, fast-failing tests that catch regressions. The project today already complies with both invariants. The risk this work mitigates is silent future regression. + +This is session 1 of 3 in the starter delivery roadmap: +1. /team archunit-rules (this session) — encode invariants as ArchUnit tests. +2. /team dependency-cleanup — `mvn dependency:analyze` sweep, declare all used deps explicitly. +3. /team opendaimon-spring-boot-starter — create the public starter module. + +## §2 Goals & Non-Goals + +Goals: +- G1. ArchUnit rule **R1** — classes in library-module packages must NOT be annotated with `@Service` or `@Component`. +- G2. ArchUnit rule **R2** — no cyclic dependencies between the four library modules: `opendaimon-common`, `opendaimon-spring-ai`, `opendaimon-telegram`, `opendaimon-rest`. +- G3. Tests run in default `mvn test` (Surefire, no profile gating, no `@Tag` exclusion). +- G4. Fail-fast on regression. Baseline today = 0 violations. + +Non-Goals: +- Rules beyond R1/R2 (Impl-suffix, layering, `*Service` naming) — deferred to a later session after baseline is green. +- Refactoring existing code (only point-fix if ArchUnit unexpectedly catches a violation; if >3 violations are found, escalate to user before fixing). +- New feature toggles, properties, or configuration knobs. +- Changes to `opendaimon-app`, `opendaimon-ui`, `opendaimon-gateway-mock` source — these modules are exempt from R1 and R2 by explicit user directive. +- Creation of a new Maven module for arch-tests (explicitly rejected). +- Publication of `opendaimon-spring-boot-starter` (separate session). +- Documentation refresh of `AGENTS.md` (the rules already exist there — this work just makes them executable). + +## §3 Stakeholders + +- Owner: ngirchev (project tech lead). +- Direct beneficiaries: contributors and AI agents working under the /team pipeline — invariants become executable, removing reliance on review-time heuristics. +- Indirect beneficiaries: downstream consumers of the future Maven Central artifacts — protected from regressions in cross-module dependency hygiene. + +## §4 Existing State (Explorer findings) + +Round B dispatched three parallel team-explorer agents. Findings: + +(a) Module roles +- `opendaimon-app` — runtime executable. Has `@SpringBootApplication`-like `Application` class at `io.github.ngirchev.opendaimon.Application`. Aggregates all other modules at compile scope. Exempt from R1/R2. +- `opendaimon-ui` — frontend module (per user directive). Contains some Java backend code under `io.github.ngirchev.opendaimon.ai.ui..` (controllers/config) but is treated as outside the rule scope. +- `opendaimon-gateway-mock` — Spring Boot auto-configuration library (`META-INF/spring/.../AutoConfiguration.imports`, `MockGatewayAutoConfig`). Used as compile-scope dep of `-app`. Exempt from R1/R2 per user directive ("просто моки"). +- `opendaimon-common`, `-spring-ai`, `-telegram`, `-rest` — library modules in scope of R1 and R2. + +(b) Test infrastructure of `opendaimon-app` +- Pre-existing `src/test/java`: single base class `AbstractContainerIT` in package `io.github.ngirchev.opendaimon.test`. +- `src/it/java` is added as an additional test-source by `build-helper-maven-plugin`; Failsafe picks up `**/*IT.java` in `verify` phase. +- Test-scoped dependencies (7): `spring-boot-starter-test`, `spring-boot-testcontainers`, `testcontainers`, `postgresql` (testcontainers), `junit-jupiter` (testcontainers), `mockwebserver` (okhttp3), `h2`. +- Surefire config in root `pluginManagement`: `forkCount=1`, `reuseForks=true`, `parallel=classes`, `threadCount=2`. Default include pattern `**/*Test.java`. +- The base Java package of `opendaimon-app` is `io.github.ngirchev.opendaimon` (no `.app` segment) — this is the package root that ArchUnit will analyse. + +(c) ArchUnit + JUnit 5 +- Library: `com.tngtech.archunit:archunit-junit5`. Latest stable: 1.4.2 (compatible with Java 21 and JUnit 5; auto-registers via ServiceLoader). +- Required `ImportOption`s: `DoNotIncludeTests` (drops `target/test-classes`), `DoNotIncludeJars` (excludes external jars; critical for performance and to keep analysis scoped to project classes). +- DSL for R1: `noClasses().that().resideInAnyPackage(...).should().beAnnotatedWith(Service.class).orShould().beAnnotatedWith(Component.class)`. +- DSL for R2: `slices().assignedFrom(SliceAssignment).should().beFreeOfCycles()` — `beFreeOfCycles()` is the correct operator (NOT `notDependOnEachOther()`, which forbids any inter-module reference and is too strict given a shared common module). + +(d) Package-root non-uniformity +Maven module names do NOT match Java package roots: +- `-common` → `io.github.ngirchev.opendaimon.common..` +- `-telegram` → `io.github.ngirchev.opendaimon.telegram..` +- `-rest` → `io.github.ngirchev.opendaimon.rest..` +- `-spring-ai` → `io.github.ngirchev.opendaimon.ai.springai..` (two segments, under `..ai..`) +- `-ui` → `io.github.ngirchev.opendaimon.ai.ui..` +- `-gateway-mock` → `io.github.ngirchev.opendaimon.ai.mock..` +- `-app` → `io.github.ngirchev.opendaimon` (Application.java directly in base) + +Implication: a naive `slices().matching("io.github.ngirchev.opendaimon.(*)..")` would collapse `-spring-ai`, `-ui`, `-gateway-mock` into a single "ai" slice. R2 therefore needs a custom `SliceAssignment` that maps package prefixes to Maven module names explicitly. + +(e) Current compliance baseline +- 0 `@Service` annotations in any library module. +- 0 `@Component` annotations in any library module. +- Two grep matches for `@Service` in `opendaimon-common/.../service/SummarizationService.java` and `ConversationThreadService.java` are JAVADOC TEXT explaining the no-`@Service` decision — not annotations. +- Conclusion: ArchUnit will pass green on first run; no fix-now action is required. + +## §5 Proposed Architecture + +(a) File layout +- One new test class: `opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java` (package `io.github.ngirchev.opendaimon.arch`). +- No new Maven module. +- No source code outside `opendaimon-app/src/test/`. + +(b) Class skeleton + +```java +@AnalyzeClasses( + packages = "io.github.ngirchev.opendaimon", + importOptions = { + ImportOption.DoNotIncludeTests.class, + ArchitectureTest.IncludeOpendaimonOnly.class + } +) +class ArchitectureTest { + + /** + * Admits exploded class files unconditionally and only those JAR entries + * whose URI contains "/opendaimon-" (our own multi-module JARs). + * Replaces ImportOption.DoNotIncludeJars: under `mvn verify` upstream + * sibling modules reach the `package` phase and are loaded as JARs, not + * exploded directories — DoNotIncludeJars filtered them out, leaving 0 + * classes in the four library-module package roots and tripping ArchUnit's + * `failOnEmptyShould=true` default. See §12(g). + */ + public static class IncludeOpendaimonOnly implements ImportOption { + @Override + public boolean includes(com.tngtech.archunit.core.importer.Location location) { + if (!location.contains(".jar")) { + return true; // exploded class file (target/classes) + } + return location.contains("/opendaimon-"); + } + } + + // R1 — see (c) + // R2 — see (d) +} +``` + +> Note: `ImportOption.DoNotIncludeJars` is replaced by the project-local `IncludeOpendaimonOnly` filter. Without this fix, the rules pass under `mvn test` (sibling modules referenced as exploded `target/classes`) but fail under `mvn verify` (sibling modules packaged into JARs, then filtered out by `DoNotIncludeJars`). The custom filter keeps performance close to `DoNotIncludeJars` (third-party JARs still skipped) while keeping correctness across both lifecycles. + +(c) R1 — no component-discovery stereotypes in library modules + +```java +@ArchTest +static final ArchRule library_modules_use_no_service_or_component_stereotypes = + noClasses() + .that().resideInAnyPackage( + "io.github.ngirchev.opendaimon.common..", + "io.github.ngirchev.opendaimon.ai.springai..", + "io.github.ngirchev.opendaimon.telegram..", + "io.github.ngirchev.opendaimon.rest..") + .should().beAnnotatedWith(org.springframework.stereotype.Service.class) + .orShould().beAnnotatedWith(org.springframework.stereotype.Component.class) + .because("Library modules export beans via @Bean methods in @Configuration classes " + + "so the upcoming opendaimon-spring-boot-starter can let downstream " + + "applications override beans via @ConditionalOnMissingBean (AGENTS.md)."); + +@ArchTest +static final ArchRule library_modules_use_no_repository_classes = + noClasses() + .that().resideInAnyPackage( + "io.github.ngirchev.opendaimon.common..", + "io.github.ngirchev.opendaimon.ai.springai..", + "io.github.ngirchev.opendaimon.telegram..", + "io.github.ngirchev.opendaimon.rest..") + .and().areNotInterfaces() + .should().beAnnotatedWith(org.springframework.stereotype.Repository.class) + .because("@Repository is only allowed on Spring Data repository interfaces."); +``` + +Notes: +- `@RestController`, `@Repository`, `@Configuration`, `@ConfigurationProperties`, `@Bean` are NOT forbidden — they are the legitimate Spring Boot library style. +- Concrete `@Repository` classes are forbidden; Spring Data repository interfaces may carry `@Repository`, although the annotation is not required when `@EnableJpaRepositories` scans the package. +- `noClasses().should().beAnnotatedWith(...)` checks the LITERAL annotation, not Spring meta-annotations. + +(d) R2 — no cyclic dependencies between library modules + +```java +private static final SliceAssignment LIBRARY_MODULES = new SliceAssignment() { + @Override + public SliceIdentifier getIdentifierOf(JavaClass cls) { + String pkg = cls.getPackageName(); + if (pkg.startsWith("io.github.ngirchev.opendaimon.common")) return SliceIdentifier.of("common"); + if (pkg.startsWith("io.github.ngirchev.opendaimon.telegram")) return SliceIdentifier.of("telegram"); + if (pkg.startsWith("io.github.ngirchev.opendaimon.rest")) return SliceIdentifier.of("rest"); + if (pkg.startsWith("io.github.ngirchev.opendaimon.ai.springai")) return SliceIdentifier.of("spring-ai"); + return SliceIdentifier.ignore(); + } + @Override + public String getDescription() { return "library modules"; } +}; + +@ArchTest +static final ArchRule library_modules_have_no_cyclic_dependencies = + slices().assignedFrom(LIBRARY_MODULES) + .should().beFreeOfCycles() + .because("Cycles between library modules would break Maven publication " + + "ordering and downstream classpath resolution."); +``` + +Notes: +- `-app`, `-ui`, `-gateway-mock` map to `SliceIdentifier.ignore()` and are excluded from cycle analysis. +- `beFreeOfCycles()` allows any DAG topology (including the expected `common` ← all-others). It only fails on actual cycles. + +(e) Maven changes +- Root `pom.xml`: add property `1.4.2` in the existing `` block, alphabetically near other `*.version` entries. +- `opendaimon-app/pom.xml`: add the dependency at the END of the test-deps section (group 5 per the comment header): + +```xml + + com.tngtech.archunit + archunit-junit5 + ${archunit.version} + test + +``` + +- No changes to any other module's `pom.xml`. + +(f) Test naming and Surefire pickup +- Class name `ArchitectureTest` matches Surefire's default `**/*Test.java` include pattern → runs in standard `mvn test`. +- Class is NOT named `*IT` → Failsafe ignores it. +- No `@Tag` annotations → not affected by the `fixture` profile. + +## §6 Data Model Changes + +None. No DB migrations, no entity changes, no schema work. + +## §7 API / Interface Changes + +None. This work touches only test code and one root pom.xml `` entry plus one `` in `opendaimon-app/pom.xml`. No public API of any module changes. No method signatures, no class moves. + +## §8 Open Questions (architectural) + +None blocking. The following items are explicitly resolved: + +- Test placement → `opendaimon-app/src/test/java/.../arch/ArchitectureTest.java`. +- Gate → default `mvn test`. +- Fix-policy on existing violations → fix-now (baseline already 0; no action). +- Rule scope → R1 + R2 only; R3/R4 deferred. +- ArchUnit-junit5 version → 1.4.2. +- Slice strategy → custom `SliceAssignment` with explicit module mapping. +- Module exemptions → `-app`, `-ui`, `-gateway-mock` exempt from both R1 and R2. + +Implementation-detail items (not blocking architecture): +- Exact `` insertion point and exact `` ordering in test deps — handled by Phase 5 developer. +- Imports of `org.springframework.stereotype.Service`/`Component` and `com.tngtech.archunit.*` types — handled by Phase 5 developer. + +## §9 Requirements + +- [x] **REQ-1** — `archunit-junit5` test dependency available in `opendaimon-app` test classpath. + - Acceptance: `./mvnw dependency:tree -pl opendaimon-app -Dincludes=com.tngtech.archunit:archunit-junit5` lists the artifact at version `1.4.2` with `scope=test`. Version is sourced from `${archunit.version}` in root `pom.xml` ``. + - Verified by: — + +- [x] **REQ-2** — R1: classes in the four library-module packages are not annotated with `@Service` or `@Component`, and concrete classes are not annotated with `@Repository`. + - Acceptance: `ArchitectureTest#library_modules_use_no_service_or_component_stereotypes` PASSES on current main; FAILS within the same test method when a synthetic `@org.springframework.stereotype.Service`-annotated class is added under any of `io.github.ngirchev.opendaimon.{common,ai.springai,telegram,rest}..`. `ArchitectureTest#library_modules_use_no_repository_classes` PASSES while allowing Spring Data repository interfaces. Negative paths are verified by QA via temporary fixture, not by leaving a violator in the tree. + - Verified by: — + +- [x] **REQ-3** — R2: no cyclic dependencies between library modules `common`, `spring-ai`, `telegram`, `rest`. + - Acceptance: `ArchitectureTest#library_modules_have_no_cyclic_dependencies` PASSES on current main. Custom `SliceAssignment` maps `..opendaimon.common..`, `..opendaimon.ai.springai..`, `..opendaimon.telegram..`, `..opendaimon.rest..` to four named slices and returns `SliceIdentifier.ignore()` for `..opendaimon.ai.ui..`, `..opendaimon.ai.mock..`, and the bare `..opendaimon` package (Application root). + - Verified by: — + +- [x] **REQ-4** — Tests run in the default `mvn test` lifecycle without profile or tag activation. + - Acceptance: `./mvnw test -pl opendaimon-app -am` lists `ArchitectureTest` in the Surefire test report. The class is named `ArchitectureTest` (Surefire's default `**/*Test.java` pattern), is NOT named `*IT` (so Failsafe ignores it), and carries no `@Tag` (so the `fixture` profile does not affect it). + - Verified by: — + +- [x] **REQ-5** — Baseline green: implementation introduces zero changes under any module's `src/main/` and tests pass on first run. + - Acceptance: After Phase 5 completion, `git diff --name-only origin/master..HEAD -- '**/src/main/**'` returns empty. `./mvnw test -pl opendaimon-app -am -Dtest=ArchitectureTest` exits 0. + - Verified by: — + +## §10 Implementation Plan (Tasks) + +- [x] **TASK-1** — Maven dependency wiring for ArchUnit + - Depends on: — + - Assignee slot: serial + - Files: + - `pom.xml` + - `opendaimon-app/pom.xml` + - Acceptance: + 1. Root `pom.xml` `` block contains a single new line `1.4.2`, placed alphabetically among existing `*.version` entries. No other property changes, no reordering of unrelated entries. + 2. `opendaimon-app/pom.xml` test-deps section (group 5 per the inline comment) contains a new dependency `com.tngtech.archunit:archunit-junit5` referencing `${archunit.version}` with `test`. Inserted as the LAST entry of group 5; no other test deps reordered. + 3. `./mvnw clean compile test-compile -pl opendaimon-app -am` exits 0. + 4. `./mvnw dependency:tree -pl opendaimon-app -Dincludes=com.tngtech.archunit:archunit-junit5` shows the dependency in test scope at version 1.4.2. + - Unit tests to add: none (this TASK is build-config only). + - Notes: see §5(e). Do NOT add `archunit-junit5` to root `` — it is an `opendaimon-app`-local test concern, not a shared library contract. Do NOT add the dep to any other module's `pom.xml`. + +- [x] **TASK-2** — `ArchitectureTest` implementation (R1 + R2) + - Depends on: TASK-1 + - Assignee slot: serial + - Files: + - `opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java` + - Acceptance: + 1. New class `io.github.ngirchev.opendaimon.arch.ArchitectureTest` exists, package-private (no `public`), annotated with `@AnalyzeClasses(packages = "io.github.ngirchev.opendaimon", importOptions = {ImportOption.DoNotIncludeTests.class, ImportOption.DoNotIncludeJars.class})`. + 2. Contains a `private static final SliceAssignment LIBRARY_MODULES = ...` exactly as specified in §5(d), mapping the four library-module package roots and returning `SliceIdentifier.ignore()` for everything else. + 3. Contains `@ArchTest static final ArchRule library_modules_use_no_service_or_component_stereotypes = ...` per §5(c), referencing `org.springframework.stereotype.Service` and `org.springframework.stereotype.Component` literally (NOT `@Component`-derived stereotypes like `@RestController`/`@Repository`), plus `library_modules_use_no_repository_classes` to ban concrete `@Repository` classes while allowing Spring Data repository interfaces. + 4. Contains `@ArchTest static final ArchRule library_modules_have_no_cyclic_dependencies = ...` per §5(d), using `slices().assignedFrom(LIBRARY_MODULES).should().beFreeOfCycles()`. + 5. Both rules carry `.because(...)` strings citing the AGENTS.md rationale (R1: starter override pattern; R2: Maven publication ordering). + 6. `./mvnw test -pl opendaimon-app -am -Dtest=ArchitectureTest` exits 0 with both `@ArchTest` rules executed (visible in Surefire `` entries). + - Unit tests to add: the `@ArchTest` static fields ARE the tests — no separate `*Test.java` companion needed. + - Notes: see §§5(b), 5(c), 5(d). Imports needed: `com.tngtech.archunit.core.domain.JavaClass`, `com.tngtech.archunit.junit.AnalyzeClasses`, `com.tngtech.archunit.junit.ArchTest`, `com.tngtech.archunit.core.importer.ImportOption`, `com.tngtech.archunit.lang.ArchRule`, `com.tngtech.archunit.library.dependencies.SliceAssignment`, `com.tngtech.archunit.library.dependencies.SliceIdentifier`, plus static imports `com.tngtech.archunit.core.domain.JavaClass.Predicates.*` if used, and `com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses`, `com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices`. Do NOT use `@ArchIgnore`. Do NOT add a meta-test that intentionally violates the rules. + +- [x] **TASK-3** — Lifecycle fix: replace `DoNotIncludeJars` with `IncludeOpendaimonOnly` + - Depends on: TASK-2 + - Assignee slot: serial + - Files: + - `opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java` + - Acceptance: + 1. Inside `ArchitectureTest`, add `public static class IncludeOpendaimonOnly implements ImportOption` exactly as specified in §5(b). Include the Javadoc citing §12(g). + 2. Replace `ImportOption.DoNotIncludeJars.class` with `ArchitectureTest.IncludeOpendaimonOnly.class` in the `@AnalyzeClasses` `importOptions = {...}` array. + 3. Add the import `com.tngtech.archunit.core.importer.Location` if not already present. + 4. `./mvnw test -pl opendaimon-app -am -Dtest=ArchitectureTest` exits 0 — both `library_modules_*` rules PASS, both check >0 classes (no "failed to check any classes" assertion). + 5. `./mvnw clean verify -pl opendaimon-app -am -Pfixture` exits 0 — Surefire phase runs `ArchitectureTest` against packaged sibling JARs; both rules PASS. This is the original regression case from the Phase 7 QA. + 6. ArchitectureTest runtime in both lifecycles stays under ~5 seconds (custom filter must NOT cause it to scan all third-party JARs). + - Unit tests to add: none (the `@ArchTest` static fields are the tests; no separate companion). + - Notes: see §5(b) updated code block and §12(g) regression analysis. Do NOT touch any pom.xml, do NOT modify any other file. Do NOT reintroduce `DoNotIncludeJars`. Do NOT use `allowEmptyShould(true)` as a workaround — that is an anti-pattern (silent failure mode). + +(§10.1 Optional dependency DAG) + +```mermaid +graph LR + TASK1[TASK-1: Maven wiring] --> TASK2[TASK-2: ArchitectureTest] +``` + +NON-OVERLAP CHECK (orchestrator-confirmed before dispatch): +- TASK-1 Files: pom.xml, opendaimon-app/pom.xml +- TASK-2 Files: opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java +- Intersection: empty. ✅ + +## §11 Q&A Log + +TBD + +## §12 Risk Register + +Findings from Phase 6 explorer audit (one explorer, full diff vs. parent branch `fsm`). Severity reclassified by orchestrator per `code-review.md` thresholds. + +(a) MEDIUM — `archunit-junit5` insertion point appears non-final in `opendaimon-app/pom.xml` +- Original explorer rating: HIGH. Reclassified to MEDIUM by orchestrator: explorer itself notes "functionally harmless"; HIGH is reserved for bugs / significant quality issues per `code-review.md`. +- Description: `archunit-junit5` (lines 171–176) is followed by `pdfbox` and `pdfbox-io` (lines 178–187). The archunit dep IS positioned correctly relative to all test-scoped dependencies (it sits immediately after `mockwebserver`, the last test-scoped entry). The visual ambiguity arises from a PRE-EXISTING structural defect — see (b) below. +- Action: none in this session. No code move would improve clarity without addressing (b), which is out of scope for `/team archunit-rules`. +- Resolution path: addressed in `/team dependency-cleanup` (session 2 of 3). + +(b) MEDIUM — Pre-existing pdfbox mis-placement [DEFERRED — out of scope] +- Description: in `opendaimon-app/pom.xml`, dependencies `pdfbox` (lines 178–182) and `pdfbox-io` (lines 183–187) lack `test` (default = `compile`) but live under the comment block that visually belongs to the test-deps section. They should either (1) carry `test` to match the comment, or (2) move above the test-deps section into group 4 (utility/runtime). Pre-existing in `master` — not introduced by this feature. +- Action: defer to `/team dependency-cleanup`. Do NOT fix here — that would extend the scope of this session. +- Reference: explorer audit, finding #4. + +(c) MEDIUM — `archunit.version` placement in root `` is not strictly alphabetical +- Description: `` (root `pom.xml:102`) is placed in the test-version sub-cluster between `` and ``. Strict alphabetical ordering across the entire `` block would put it earlier (before `byte-buddy`, `caffeine`). The current placement co-locates it with related test-version entries (`okhttp`, `mockito`, `testcontainers`). +- Action: accepted as-is. Co-location with peer test-version entries is a defensible local convention. No fix. +- Reference: explorer audit, MEDIUM finding. + +(d) LOW — Rule field naming uses snake_case +- Description: `library_modules_use_no_service_or_component_stereotypes`, `library_modules_use_no_repository_classes`, and `library_modules_have_no_cyclic_dependencies` use underscore-separated names rather than the project-wide `shouldDoSomethingWhenCondition` convention. +- Action: accepted. ArchUnit's `static final ArchRule` fields conventionally use descriptive snake_case (per ArchUnit user-guide examples). The project test-method convention does not apply to fields. +- Reference: explorer audit, LOW finding. + +(e) LOW — Inline FQN references for `Service.class` / `Component.class` +- Description: `org.springframework.stereotype.Service.class` and `Component.class` referenced via fully-qualified names inline (`ArchitectureTest.java:58-59`) rather than as `import` statements at the top. +- Action: accepted. Stylistic preference; no functional impact, no readability concern given the rule is short. +- Reference: explorer audit, LOW finding. + +(g) HIGH (resolved by TASK-3) — `DoNotIncludeJars` lifecycle-dependent failure +- Description: under `mvn verify -Pfixture` the original `ImportOption.DoNotIncludeJars` filtered out our own packaged sibling JARs (`opendaimon-common-1.0.0-SNAPSHOT.jar`, etc.) because Maven `package` phase ran before Surefire. Result: ArchitectureTest's `that().resideInAnyPackage(...)` matcher saw 0 classes in all four library packages, and ArchUnit's default `failOnEmptyShould=true` raised AssertionError on both `@ArchTest` rules. The rule logic itself is correct — only the ImportOption choice was wrong. +- Detected by: Phase 7 QA (`./mvnw clean verify -pl opendaimon-app -am -Pfixture`). +- Resolution: TASK-3 introduces `ArchitectureTest.IncludeOpendaimonOnly implements ImportOption` admitting exploded class files unconditionally and JARs only when URI contains `/opendaimon-`. See §5(b) updated code block. +- Lesson learned: ArchUnit `ImportOption` filters interact with Maven lifecycle phase. Any future `ImportOption` choice must be validated under BOTH `mvn test` and `mvn verify -Pfixture` before declaring DONE. Phase 1 explorer #3 flagged a related risk (siblings unbuilt → empty analysis) but missed the inverse case (siblings packaged → filtered out). Add lifecycle-coverage to the explorer checklist for future ArchUnit work. + +§12 STATUS — no open CRITICAL or HIGH findings (the HIGH finding (g) is being resolved by TASK-3 in a Phase-5-revisit loop; QA will re-run after TASK-3 ticks). + +## §13 Definition of Done + +All five REQs verified by team-qa-tester after TASK-3 remediation. Both lifecycle modes green. + +| REQ | Verifying Command | Result | +|---|---|---| +| REQ-1 | `./mvnw dependency:tree -pl opendaimon-app -am -Dincludes=com.tngtech.archunit:archunit-junit5` | PASS — `com.tngtech.archunit:archunit-junit5:jar:1.4.2:test` listed | +| REQ-2 | `./mvnw test -pl opendaimon-app -am -Dtest=ArchitectureTest` (`library_modules_use_no_service_or_component_stereotypes`, `library_modules_use_no_repository_classes`) | PASS — 3.046s under `mvn test`; 2.44s under `mvn verify -Pfixture` | +| REQ-3 | `./mvnw test -pl opendaimon-app -am -Dtest=ArchitectureTest` (`library_modules_have_no_cyclic_dependencies`) | PASS — 0.136s under `mvn test`; 0.132s under `mvn verify -Pfixture` | +| REQ-4 | `./mvnw test -pl opendaimon-app -am` (no `-Dtest`, no profile) — Surefire picks up `*Test.java` automatically, no `@Tag` filtering | PASS — `ArchitectureTest` runs in default `mvn test` lifecycle, 2 tests / 0 failures | +| REQ-5 | `git diff --name-only HEAD -- '**/src/main/**'` + `git ls-files --others --exclude-standard \| grep '/src/main/'` | PASS — both commands return empty; zero `src/main/` changes in any module | + +Anti-regression checks: +- Full `opendaimon-app` Surefire suite: BUILD SUCCESS in 32.810s. +- Fixture suite (`mvn clean verify -pl opendaimon-app -am -Pfixture`): BUILD SUCCESS in 01:05 min, ArchitectureTest 2.576s, both rules executed against packaged opendaimon-* sibling JARs without `failOnEmptyShould` trip. + +Implementation summary: +- 3 production files touched: `pom.xml` (1 property added), `opendaimon-app/pom.xml` (1 test-dep added), `opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java` (created, 1 lifecycle fix applied). +- 0 changes under any `src/main/` of any module. +- 0 new Maven modules; 0 new feature toggles; 0 changes to existing `*AutoConfig` classes. + +Status: ready for `/commit` (handled outside the /team pipeline per AGENTS.md "no auto-commit" rule). + +## §14 Activity Log + +- 2026-04-28T00:00:00Z TASK-1 completed by team-developer: archunit.version=1.4.2 in root pom.xml, archunit-junit5 test dep in opendaimon-app/pom.xml. Both acceptance checks (mvn compile + dependency:tree) green. +- 2026-04-28T00:01:00Z TASK-2 completed by team-developer: ArchitectureTest.java created at opendaimon-app/src/test/java/.../arch/. Both @ArchTest rules executed and PASS on current main (R1: 2.571s, R2: 0.138s, total 2.713s). Zero changes under src/main/. +- 2026-04-28T00:02:00Z Phase 6 verification: 1 explorer audited TASK-1 + TASK-2 against §10 Files: globs. Original ratings: 1 HIGH, 1 MEDIUM, 2 LOW. Orchestrator reclassified HIGH → MEDIUM (functionally harmless per explorer's own note). +- 2026-04-28T00:03:00Z Pre-existing pdfbox mis-placement in opendaimon-app/pom.xml deferred to /team dependency-cleanup (session 2 of 3). No code move performed — archunit-junit5 already positioned correctly relative to test-scoped deps. +- 2026-04-28T00:04:00Z Phase 7 QA returned BLOCKED: production regression on REQ-2 / REQ-3 under `mvn verify -Pfixture`. Mechanism: `ImportOption.DoNotIncludeJars` filters packaged opendaimon-* JARs once Maven advances to `package` phase; ArchitectureTest's `failOnEmptyShould=true` default trips. Detected via `./mvnw clean verify -pl opendaimon-app -am -Pfixture`. +- 2026-04-28T00:05:00Z TASK-3 authored to resolve §12(g): replace `DoNotIncludeJars` with project-local `IncludeOpendaimonOnly` ImportOption. Pipeline returns to Phase 5 for TASK-3, then re-runs Phase 6 (verification) and Phase 7 (QA). +- 2026-04-28T00:06:00Z TASK-3 completed by team-developer: ArchitectureTest now uses IncludeOpendaimonOnly ImportOption. Both lifecycles verified — mvn test PASS (2.661s), mvn clean verify -Pfixture PASS (ArchitectureTest 2.487s, full reactor 01:09 min). §12(g) regression resolved. +- 2026-04-28T00:07:00Z Phase 7 QA re-run after TASK-3: ALL 5 REQs PASS. UNIT RUN: PASS, FIXTURE RUN: PASS, MAPPING UPDATE: no. §12(g) regression closed. §13 Definition of Done populated with verification table. +- 2026-04-28T00:08:00Z Phase 8 closure: §14 closure notes authored, frontmatter status → done, base_branch metadata corrected to `fsm` (parent branch). Pipeline complete; orchestrator hands off to user for /commit. + +--- + +#### Closure Notes (Phase 8) + +- **Use-case docs to update**: none. This feature does not touch any `docs/usecases/*.md` — ArchUnit rules are infrastructure tests, not user-facing behavior. +- **Module docs to update**: none. No `*_MODULE.md` documentation exists for `opendaimon-app/arch/` (test infrastructure), and `AGENTS.md` already documents the architectural invariants textually. The new `ArchitectureTest.java` is self-documenting via its class-level Javadoc and inline `.because(...)` rule descriptions. +- **Suggested commit type** (per `.claude/rules/git-workflow.md`): `test` — primary deliverable is a test class enforcing architectural invariants; secondary build-config additions in two `pom.xml` files support that test. +- **Suggested commit subject**: `test: add ArchUnit rules for stereotypes and module cycles` +- **Suggested commit body** (HEREDOC-friendly): + +``` +Add ArchitectureTest in opendaimon-app/src/test/java/.../arch/ enforcing +two invariants from AGENTS.md as executable JUnit 5 / ArchUnit rules: + + R1: classes in library-module packages (common, ai.springai, telegram, + rest) must not be annotated with @Service or @Component — beans + must be exported via @Bean methods so the future + opendaimon-spring-boot-starter can let downstream consumers + override them via @ConditionalOnMissingBean. + + R2: no cyclic dependencies between the four library modules — checked + via custom SliceAssignment that maps each Maven module to its + package root and ignores opendaimon-app, -ui, -gateway-mock. + +Custom IncludeOpendaimonOnly ImportOption admits exploded class files +and only opendaimon-* JARs, so rules pass under both `mvn test` +(siblings as target/classes) and `mvn verify -Pfixture` (siblings as +packaged JARs). Replaces ImportOption.DoNotIncludeJars which silently +filtered our own JARs in the verify lifecycle. + +Baseline: 0 violations on current main. Tests run in default `mvn test` +in ~3 seconds, no profile gating, no @Tag. + +Maven changes: + - root pom.xml: 1.4.2 + - opendaimon-app/pom.xml: archunit-junit5 in test scope + +Session 1 of 3 in starter delivery roadmap; sessions 2 and 3 are +/team dependency-cleanup and /team opendaimon-spring-boot-starter. +``` diff --git a/opendaimon-app/pom.xml b/opendaimon-app/pom.xml index e6d4335d..8d07b1e8 100644 --- a/opendaimon-app/pom.xml +++ b/opendaimon-app/pom.xml @@ -27,36 +27,41 @@ UTF-8 UTF-8 - - 3.0.5 - + io.github.ngirchev opendaimon-telegram ${project.version} + runtime io.github.ngirchev opendaimon-rest ${project.version} + runtime io.github.ngirchev opendaimon-ui ${project.version} + runtime io.github.ngirchev opendaimon-spring-ai ${project.version} + runtime io.github.ngirchev opendaimon-gateway-mock ${project.version} + runtime @@ -64,39 +69,62 @@ dotenv - + + + org.springframework.boot + spring-boot + + + org.springframework.boot + spring-boot-autoconfigure + + + + + org.springframework + spring-context + + + org.springframework.boot spring-boot-starter-validation + runtime org.springframework.boot spring-boot-starter-data-jpa + runtime org.springframework.boot spring-boot-starter-web + runtime org.springframework.boot spring-boot-starter-actuator + runtime - - + - org.springdoc - springdoc-openapi-starter-webmvc-ui + org.springframework.boot + spring-boot-starter-data-redis + runtime + - jakarta.xml.bind - jakarta.xml.bind-api + org.springdoc + springdoc-openapi-starter-webmvc-ui + runtime - + org.postgresql postgresql + runtime org.flywaydb @@ -105,42 +133,77 @@ org.flywaydb flyway-database-postgresql - - - com.h2database - h2 - test + runtime - - org.projectlombok - lombok - - io.minio minio - ${minio.version} + runtime - + - org.springframework.boot - spring-boot-starter-data-redis + org.slf4j + slf4j-api - - + + + ch.qos.logback + logback-classic + + + ch.qos.logback + logback-core + + net.logstash.logback logstash-logback-encoder - 7.4 + runtime - + + + org.projectlombok + lombok + provided + true + + + + + org.apache.pdfbox + pdfbox + runtime + + + org.apache.pdfbox + pdfbox-io + runtime + + + commons-logging + commons-logging + + + + + + + org.springframework + spring-test + test + + + org.springframework.boot + spring-boot-test + test + org.springframework.boot - spring-boot-starter-test + spring-boot-test-autoconfigure test @@ -148,6 +211,21 @@ spring-boot-testcontainers test + + org.junit.jupiter + junit-jupiter-api + test + + + org.mockito + mockito-core + test + + + org.assertj + assertj-core + test + org.testcontainers testcontainers @@ -163,27 +241,72 @@ junit-jupiter test + + com.h2database + h2 + test + com.squareup.okhttp3 - mockwebserver + okhttp test - - org.apache.pdfbox - pdfbox - ${pdfbox.version} + com.squareup.okhttp3 + mockwebserver + test - org.apache.pdfbox - pdfbox-io - ${pdfbox.version} + com.tngtech.archunit + archunit-junit5 + ${archunit.version} + test - + + + org.apache.maven.plugins + maven-dependency-plugin + + + org.springframework:* + org.springframework.boot:* + org.springframework.data:* + org.springframework.ai:* + org.telegram:* + io.projectreactor:* + io.micrometer:* + io.github.ngirchev:* + jakarta.persistence:* + com.tngtech.archunit:* + + + io.github.ngirchev:opendaimon-ui + org.springframework.boot:spring-boot-starter-* + org.springdoc:springdoc-openapi-starter-webmvc-ui + org.postgresql:postgresql + org.flywaydb:flyway-database-postgresql + io.minio:minio + net.logstash.logback:logstash-logback-encoder + org.apache.pdfbox:pdfbox-io + org.springframework.boot:spring-boot-testcontainers + org.testcontainers:junit-jupiter + com.h2database:h2 + com.tngtech.archunit:archunit-junit5 + + + org.springframework:spring-core + org.springframework:spring-beans + + + + org.springframework.boot spring-boot-maven-plugin diff --git a/opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java b/opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java new file mode 100644 index 00000000..ade33f2a --- /dev/null +++ b/opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java @@ -0,0 +1,167 @@ +package io.github.ngirchev.opendaimon.arch; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; +import static com.tngtech.archunit.library.Architectures.layeredArchitecture; +import static com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices; + +import com.tngtech.archunit.core.domain.Dependency; +import com.tngtech.archunit.core.domain.JavaClass; +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.core.importer.Location; +import com.tngtech.archunit.junit.AnalyzeClasses; +import com.tngtech.archunit.junit.ArchTest; +import com.tngtech.archunit.lang.ArchCondition; +import com.tngtech.archunit.lang.ArchRule; +import com.tngtech.archunit.lang.ConditionEvents; +import com.tngtech.archunit.lang.SimpleConditionEvent; +import com.tngtech.archunit.library.dependencies.SliceAssignment; +import com.tngtech.archunit.library.dependencies.SliceIdentifier; + +import java.util.Set; +import java.util.TreeSet; + +/** + * Executable architectural invariants for the {@code opendaimon-*} library modules. + * + *

Library modules are published to Maven Central and consumed independently, so this + * test codifies the module and bean-wiring boundaries from AGENTS.md. + */ +@AnalyzeClasses( + packages = "io.github.ngirchev.opendaimon", + importOptions = { + ImportOption.DoNotIncludeTests.class, + ArchitectureTest.IncludeOpendaimonOnly.class + } +) +class ArchitectureTest { + + /** + * Admits exploded class files unconditionally and only those JAR entries + * whose URI contains "/opendaimon-" (our own multi-module JARs). + */ + public static class IncludeOpendaimonOnly implements ImportOption { + @Override + public boolean includes(Location location) { + if (!location.contains(".jar")) { + return true; + } + return location.contains("/opendaimon-"); + } + } + + private static final SliceAssignment LIBRARY_MODULES = new SliceAssignment() { + @Override + public SliceIdentifier getIdentifierOf(JavaClass cls) { + String pkg = cls.getPackageName(); + if (pkg.startsWith("io.github.ngirchev.opendaimon.common")) { + return SliceIdentifier.of("common"); + } + if (pkg.startsWith("io.github.ngirchev.opendaimon.telegram")) { + return SliceIdentifier.of("telegram"); + } + if (pkg.startsWith("io.github.ngirchev.opendaimon.rest")) { + return SliceIdentifier.of("rest"); + } + if (pkg.startsWith("io.github.ngirchev.opendaimon.ai.springai")) { + return SliceIdentifier.of("spring-ai"); + } + if (pkg.startsWith("io.github.ngirchev.opendaimon.ai.ui")) { + return SliceIdentifier.of("ui"); + } + return SliceIdentifier.ignore(); + } + + @Override + public String getDescription() { + return "published library modules"; + } + }; + + private static final ArchCondition DEPEND_ON_AT_MOST_ONE_DELIVERY_CHANNEL = + new ArchCondition<>("depend on at most one delivery channel module") { + @Override + public void check(JavaClass item, ConditionEvents events) { + if (item.getPackageName().equals("io.github.ngirchev.opendaimon")) { + return; + } + Set deliveryChannels = new TreeSet<>(); + for (Dependency dependency : item.getDirectDependenciesFromSelf()) { + String packageName = dependency.getTargetClass().getPackageName(); + if (packageName.startsWith("io.github.ngirchev.opendaimon.telegram")) { + deliveryChannels.add("telegram"); + } + if (packageName.startsWith("io.github.ngirchev.opendaimon.rest")) { + deliveryChannels.add("rest"); + } + } + if (deliveryChannels.size() > 1) { + events.add(SimpleConditionEvent.violated( + item, + item.getName() + " depends on multiple delivery channels: " + deliveryChannels)); + } + } + }; + + @ArchTest + static final ArchRule library_modules_use_no_service_or_component_stereotypes = + noClasses() + .that().resideInAnyPackage( + "io.github.ngirchev.opendaimon.common..", + "io.github.ngirchev.opendaimon.ai.springai..", + "io.github.ngirchev.opendaimon.telegram..", + "io.github.ngirchev.opendaimon.rest..", + "io.github.ngirchev.opendaimon.ai.ui..") + .should().beAnnotatedWith(org.springframework.stereotype.Service.class) + .orShould().beAnnotatedWith(org.springframework.stereotype.Component.class) + .because("Library modules export beans via @Bean methods in @Configuration classes."); + + @ArchTest + static final ArchRule library_modules_use_no_repository_classes = + noClasses() + .that().resideInAnyPackage( + "io.github.ngirchev.opendaimon.common..", + "io.github.ngirchev.opendaimon.ai.springai..", + "io.github.ngirchev.opendaimon.telegram..", + "io.github.ngirchev.opendaimon.rest..", + "io.github.ngirchev.opendaimon.ai.ui..") + .and().areNotInterfaces() + .should().beAnnotatedWith(org.springframework.stereotype.Repository.class) + .because("@Repository is only allowed on Spring Data repository interfaces."); + + @ArchTest + static final ArchRule library_modules_have_no_cyclic_dependencies = + slices().assignedFrom(LIBRARY_MODULES) + .should().beFreeOfCycles() + .because("Cycles between published library modules break independent consumption."); + + @ArchTest + static final ArchRule telegram_module_does_not_depend_on_rest_module = + noClasses() + .that().resideInAPackage("io.github.ngirchev.opendaimon.telegram..") + .should().dependOnClassesThat().resideInAPackage("io.github.ngirchev.opendaimon.rest..") + .because("Delivery channels must stay independently consumable."); + + @ArchTest + static final ArchRule rest_module_does_not_depend_on_telegram_module = + noClasses() + .that().resideInAPackage("io.github.ngirchev.opendaimon.rest..") + .should().dependOnClassesThat().resideInAPackage("io.github.ngirchev.opendaimon.telegram..") + .because("Delivery channels must stay independently consumable."); + + @ArchTest + static final ArchRule only_app_depends_on_multiple_delivery_channel_modules = + classes() + .that().resideInAPackage("io.github.ngirchev.opendaimon..") + .should(DEPEND_ON_AT_MOST_ONE_DELIVERY_CHANNEL) + .because("Only the runtime app may compose multiple delivery channels."); + + @ArchTest + static final ArchRule repositories_are_accessed_only_from_service_or_config = + layeredArchitecture().consideringAllDependencies() + .layer("Repository").definedBy("io.github.ngirchev.opendaimon..repository..") + .layer("Service").definedBy("io.github.ngirchev.opendaimon..service..") + .layer("Config").definedBy("io.github.ngirchev.opendaimon..config..") + .whereLayer("Repository").mayOnlyBeAccessedByLayers("Service", "Config") + .because("Repository access must stay behind service APIs and explicit @Bean configuration."); +} diff --git a/opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/it/springai/SpringAIGatewayStreamingRealContextIT.java b/opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/it/springai/SpringAIGatewayStreamingRealContextIT.java index e8f0c6f2..67b6985c 100644 --- a/opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/it/springai/SpringAIGatewayStreamingRealContextIT.java +++ b/opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/it/springai/SpringAIGatewayStreamingRealContextIT.java @@ -3,15 +3,21 @@ import lombok.extern.slf4j.Slf4j; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; +import org.springframework.ai.model.tool.ToolCallingManager; +import org.springframework.ai.openai.OpenAiChatModel; +import org.springframework.ai.openai.OpenAiChatOptions; +import org.springframework.ai.openai.api.OpenAiApi; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.Bean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringBootConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; import org.springframework.test.context.TestPropertySource; @@ -54,6 +60,7 @@ CoreJpaConfig.class, SpringAIFlywayConfig.class }) +@ActiveProfiles("integration-test") @TestPropertySource(properties = { "spring.autoconfigure.exclude=org.springframework.ai.model.chat.memory.autoconfigure.ChatMemoryAutoConfiguration", "spring.ai.ollama.base-url=http://127.0.0.1:0", @@ -101,8 +108,7 @@ class SpringAIGatewayStreamingRealContextIT extends AbstractContainerIT { @BeforeAll static void startMockServer() throws IOException { - mockWebServer = new MockWebServer(); - mockWebServer.start(); + ensureMockServerStarted(); } @AfterAll @@ -114,10 +120,26 @@ static void shutdownMockServer() throws IOException { @DynamicPropertySource static void setOpenAiBaseUrl(DynamicPropertyRegistry registry) { - registry.add("spring.ai.openai.base-url", () -> mockWebServer.url("/").toString()); + registry.add("spring.ai.openai.base-url", SpringAIGatewayStreamingRealContextIT::mockServerBaseUrl); registry.add("spring.ai.openai.api-key", () -> "test"); } + private static synchronized void ensureMockServerStarted() throws IOException { + if (mockWebServer == null) { + mockWebServer = new MockWebServer(); + mockWebServer.start(); + } + } + + private static String mockServerBaseUrl() { + try { + ensureMockServerStarted(); + } catch (IOException e) { + throw new IllegalStateException("Failed to start OpenAI mock server", e); + } + return mockWebServer.url("/").toString(); + } + @Autowired private SpringAIGateway springAIGateway; @@ -217,5 +239,21 @@ private Map createBodyWithMaxPrice() { "org.springframework.ai.model.openai.autoconfigure.OpenAiModerationAutoConfiguration" }) static class TestConfig { + @Bean + OpenAiChatModel openAiChatModel(ToolCallingManager toolCallingManager) { + OpenAiApi openAiApi = OpenAiApi.builder() + .baseUrl(mockServerBaseUrl()) + .apiKey("test") + .completionsPath("/v1/chat/completions") + .build(); + + return OpenAiChatModel.builder() + .openAiApi(openAiApi) + .defaultOptions(OpenAiChatOptions.builder() + .model("openrouter/auto") + .build()) + .toolCallingManager(toolCallingManager) + .build(); + } } } diff --git a/opendaimon-common/pom.xml b/opendaimon-common/pom.xml index 5f874553..56148ebc 100644 --- a/opendaimon-common/pom.xml +++ b/opendaimon-common/pom.xml @@ -30,49 +30,79 @@ + - org.springframework.boot - spring-boot + io.github.ngirchev + fsm + + + + + org.springframework + spring-core - org.springframework.boot - spring-boot-autoconfigure + org.springframework + spring-beans + + + org.springframework + spring-context + + + org.springframework + spring-tx org.springframework spring-web - + + org.springframework + spring-webflux + + + + io.projectreactor + reactor-core + + + org.reactivestreams + reactive-streams + + org.springframework.boot - spring-boot-starter-webflux + spring-boot - - org.springframework.boot - spring-boot-starter-aop + spring-boot-autoconfigure + + + org.springframework.data + spring-data-commons + org.springframework.data spring-data-jpa + + org.springframework.ai spring-ai-model + + jakarta.validation jakarta.validation-api - - org.hibernate.validator - hibernate-validator - - - + jakarta.persistence jakarta.persistence-api @@ -81,79 +111,118 @@ org.hibernate.orm hibernate-core - - org.postgresql - postgresql - - - jakarta.xml.bind - jakarta.xml.bind-api - - + org.flywaydb flyway-core - + org.slf4j slf4j-api + + org.projectlombok lombok + provided true + + - io.vavr - vavr + org.jetbrains + annotations - + - io.github.ngirchev - fsm + jakarta.annotation + jakarta.annotation-api + - io.micrometer - micrometer-registry-prometheus + com.fasterxml.jackson.core + jackson-databind + + + + + io.vavr + vavr - + + + io.micrometer + micrometer-core + + com.github.ben-manes.caffeine caffeine - ${caffeine.version} - + io.minio minio - ${minio.version} true - - io.github.resilience4j - resilience4j-spring-boot2 - ${resilience4j.version} - io.github.resilience4j resilience4j-bulkhead - ${resilience4j.version} + + org.springframework + spring-test + test + org.springframework.boot spring-boot-test test + + org.hibernate.validator + hibernate-validator + test + + + org.junit.jupiter + junit-jupiter-api + test + + + com.tngtech.archunit + archunit + ${archunit.version} + test + + + com.tngtech.archunit + archunit-junit5-api + ${archunit.version} + test + + + com.tngtech.archunit + archunit-junit5-engine + ${archunit.version} + test + + + org.mockito + mockito-core + test + org.mockito mockito-junit-jupiter @@ -186,6 +255,31 @@ + + org.apache.maven.plugins + maven-dependency-plugin + + + + com.tngtech.archunit:archunit-junit5-engine + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + + true + + org.springframework.boot:spring-boot-starter* + + + + + - \ No newline at end of file + diff --git a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/agent/persistence/AgentExecutionRepository.java b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/agent/persistence/AgentExecutionRepository.java index 13aa6d1e..d09ea063 100644 --- a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/agent/persistence/AgentExecutionRepository.java +++ b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/agent/persistence/AgentExecutionRepository.java @@ -1,14 +1,12 @@ package io.github.ngirchev.opendaimon.common.agent.persistence; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; import java.util.List; /** * Repository for agent execution persistence. */ -@Repository public interface AgentExecutionRepository extends JpaRepository { List findByConversationIdOrderByStartedAtDesc(String conversationId); diff --git a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/AssistantRoleRepository.java b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/AssistantRoleRepository.java index 3128efb0..d979d314 100644 --- a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/AssistantRoleRepository.java +++ b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/AssistantRoleRepository.java @@ -4,7 +4,6 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; import io.github.ngirchev.opendaimon.common.model.AssistantRole; import io.github.ngirchev.opendaimon.common.model.User; @@ -12,7 +11,6 @@ import java.util.List; import java.util.Optional; -@Repository public interface AssistantRoleRepository extends JpaRepository { /** diff --git a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/BugreportRepository.java b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/BugreportRepository.java index 6d39eb0c..40589c20 100644 --- a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/BugreportRepository.java +++ b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/BugreportRepository.java @@ -1,14 +1,12 @@ package io.github.ngirchev.opendaimon.common.repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; import io.github.ngirchev.opendaimon.common.model.Bugreport; import io.github.ngirchev.opendaimon.common.model.BugreportType; import io.github.ngirchev.opendaimon.common.model.User; import java.util.List; -@Repository public interface BugreportRepository extends JpaRepository { List findByUserOrderByCreatedAtDesc(User user); diff --git a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/ConversationThreadRepository.java b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/ConversationThreadRepository.java index a7ff5106..51dc70f7 100644 --- a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/ConversationThreadRepository.java +++ b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/ConversationThreadRepository.java @@ -3,7 +3,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; import io.github.ngirchev.opendaimon.common.model.ConversationThread; import io.github.ngirchev.opendaimon.common.model.ThreadScopeKind; import io.github.ngirchev.opendaimon.common.model.User; @@ -12,7 +11,6 @@ import java.util.List; import java.util.Optional; -@Repository public interface ConversationThreadRepository extends JpaRepository { /** diff --git a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/OpenDaimonMessageRepository.java b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/OpenDaimonMessageRepository.java index 66642bfe..cb181dac 100644 --- a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/OpenDaimonMessageRepository.java +++ b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/OpenDaimonMessageRepository.java @@ -3,7 +3,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; import io.github.ngirchev.opendaimon.common.model.ConversationThread; import io.github.ngirchev.opendaimon.common.model.OpenDaimonMessage; import io.github.ngirchev.opendaimon.common.model.MessageRole; @@ -16,7 +15,6 @@ * Repository for dialog messages. * Replaces UserRequestRepository and ServiceResponseRepository. */ -@Repository public interface OpenDaimonMessageRepository extends JpaRepository { /** diff --git a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/UserRecentModelRepository.java b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/UserRecentModelRepository.java index 090b89e8..bbc9b682 100644 --- a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/UserRecentModelRepository.java +++ b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/UserRecentModelRepository.java @@ -5,12 +5,10 @@ import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; import java.util.List; import java.util.Optional; -@Repository public interface UserRecentModelRepository extends JpaRepository { /** diff --git a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/UserRepository.java b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/UserRepository.java index 2d847849..d678b415 100644 --- a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/UserRepository.java +++ b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/repository/UserRepository.java @@ -1,14 +1,12 @@ package io.github.ngirchev.opendaimon.common.repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; import io.github.ngirchev.opendaimon.common.model.User; /** * Repository for base user table. * Supports polymorphic queries for TelegramUser and RestUser. */ -@Repository public interface UserRepository extends JpaRepository { } diff --git a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/service/ConversationThreadService.java b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/service/ConversationThreadService.java index 2fb62b73..83e2dc80 100644 --- a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/service/ConversationThreadService.java +++ b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/service/ConversationThreadService.java @@ -186,9 +186,29 @@ public Optional findCurrentThread(ThreadScopeKind scopeKind, .filter(this::isThreadStillActive); } + /** + * Returns all threads for a scope, newest activity first. + */ + @Transactional(readOnly = true) + public List findThreads(ThreadScopeKind scopeKind, Long scopeId) { + validateScope(scopeKind, scopeId); + return threadRepository.findByScopeKindAndScopeIdOrderByLastActivityAtDesc(scopeKind, scopeId); + } + + /** + * Closes the current active thread for a scope if one exists. + */ + public boolean closeCurrentThread(ThreadScopeKind scopeKind, Long scopeId) { + validateScope(scopeKind, scopeId); + Optional currentThread = threadRepository.findMostRecentActiveThread(scopeKind, scopeId); + currentThread.ifPresent(this::closeThread); + return currentThread.isPresent(); + } + /** * Finds thread by key. */ + @Transactional(readOnly = true) public Optional findByThreadKey(String threadKey) { return threadRepository.findByThreadKey(threadKey); } diff --git a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/service/OpenDaimonMessageService.java b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/service/OpenDaimonMessageService.java index f45645e1..8a771e12 100644 --- a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/service/OpenDaimonMessageService.java +++ b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/service/OpenDaimonMessageService.java @@ -398,6 +398,19 @@ public List findRagDocumentIds(ConversationThread thread) { return result; } + @Transactional(readOnly = true) + public List findByThreadOrderBySequenceNumberAsc(ConversationThread thread) { + return messageRepository.findByThreadOrderBySequenceNumberAsc(thread); + } + + @Transactional(readOnly = true) + public List findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc( + ConversationThread thread, + Integer minSequenceNumber) { + return messageRepository.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc( + thread, minSequenceNumber); + } + /** * Stores RAG documentIds and filenames in the metadata of a USER message. * diff --git a/opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/bulkhead/config/BulkHeadPropertiesTest.java b/opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/bulkhead/config/BulkHeadPropertiesTest.java index a0207155..6b5c3f61 100644 --- a/opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/bulkhead/config/BulkHeadPropertiesTest.java +++ b/opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/bulkhead/config/BulkHeadPropertiesTest.java @@ -1,5 +1,9 @@ package io.github.ngirchev.opendaimon.bulkhead.config; +import jakarta.validation.Validation; +import jakarta.validation.ValidatorFactory; +import org.hibernate.validator.HibernateValidator; +import org.hibernate.validator.messageinterpolation.ParameterMessageInterpolator; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -35,6 +39,16 @@ static class TestConfiguration { @Autowired private BulkHeadProperties properties; + @Test + void testValidationProvider_ShouldBeAvailableForConfigurationPropertiesBinding() { + try (ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class) + .configure() + .messageInterpolator(new ParameterMessageInterpolator()) + .buildValidatorFactory()) { + assertNotNull(validatorFactory.getValidator(), "Validation provider must create a validator"); + } + } + @Test void testBulkHeadProperties_ShouldLoadAllInstances() { // Assert diff --git a/opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/common/arch/CommonArchitectureTest.java b/opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/common/arch/CommonArchitectureTest.java new file mode 100644 index 00000000..68e6e3f0 --- /dev/null +++ b/opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/common/arch/CommonArchitectureTest.java @@ -0,0 +1,195 @@ +package io.github.ngirchev.opendaimon.common.arch; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.methods; +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; +import static com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices; + +import com.tngtech.archunit.core.domain.JavaClass; +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.junit.AnalyzeClasses; +import com.tngtech.archunit.junit.ArchTest; +import com.tngtech.archunit.lang.ArchCondition; +import com.tngtech.archunit.lang.ArchRule; +import com.tngtech.archunit.lang.ConditionEvents; +import com.tngtech.archunit.lang.SimpleConditionEvent; +import com.tngtech.archunit.library.dependencies.SliceAssignment; +import com.tngtech.archunit.library.dependencies.SliceIdentifier; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Controller; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.RestController; + +@AnalyzeClasses( + packages = { + "io.github.ngirchev.opendaimon.common", + "io.github.ngirchev.opendaimon.bulkhead" + }, + importOptions = { + ImportOption.DoNotIncludeTests.class, + ImportOption.DoNotIncludeJars.class + } +) +class CommonArchitectureTest { + + private static final String[] COMMON_MODULE_PACKAGES = { + "io.github.ngirchev.opendaimon.common..", + "io.github.ngirchev.opendaimon.bulkhead.." + }; + + private static final String[] DOWNSTREAM_MODULE_PACKAGES = { + "io.github.ngirchev.opendaimon.ai.springai..", + "io.github.ngirchev.opendaimon.ai.ui..", + "io.github.ngirchev.opendaimon.telegram..", + "io.github.ngirchev.opendaimon.rest.." + }; + + private static final String[] COMMON_CONFIG_PACKAGES = { + "io.github.ngirchev.opendaimon.common.config..", + "io.github.ngirchev.opendaimon.common.storage.config..", + "io.github.ngirchev.opendaimon.bulkhead.config.." + }; + + private static final ArchCondition HAVE_COMMON_CONFIGURATION_PREFIX = + new ArchCondition<>("have an open-daimon.common configuration prefix") { + @Override + public void check(JavaClass item, ConditionEvents events) { + ConfigurationProperties annotation = item.getAnnotationOfType(ConfigurationProperties.class); + String prefix = annotation.prefix().isBlank() ? annotation.value() : annotation.prefix(); + if (!prefix.startsWith("open-daimon.common")) { + events.add(SimpleConditionEvent.violated( + item, + item.getName() + " uses configuration prefix '" + prefix + "'")); + } + } + }; + + private static final SliceAssignment COMMON_RUNTIME_SLICES = new SliceAssignment() { + @Override + public SliceIdentifier getIdentifierOf(JavaClass javaClass) { + String packageName = javaClass.getPackageName(); + if (packageName.startsWith("io.github.ngirchev.opendaimon.bulkhead")) { + return SliceIdentifier.of("bulkhead"); + } + if (packageName.startsWith("io.github.ngirchev.opendaimon.common.agent")) { + return SliceIdentifier.of("agent"); + } + if (packageName.startsWith("io.github.ngirchev.opendaimon.common.ai")) { + return SliceIdentifier.of("ai"); + } + if (packageName.startsWith("io.github.ngirchev.opendaimon.common.command")) { + return SliceIdentifier.of("command"); + } + if (packageName.startsWith("io.github.ngirchev.opendaimon.common.meter")) { + return SliceIdentifier.of("meter"); + } + if (packageName.startsWith("io.github.ngirchev.opendaimon.common.model")) { + return SliceIdentifier.of("model"); + } + if (packageName.startsWith("io.github.ngirchev.opendaimon.common.repository")) { + return SliceIdentifier.of("repository"); + } + if (packageName.startsWith("io.github.ngirchev.opendaimon.common.service")) { + return SliceIdentifier.of("service"); + } + if (packageName.startsWith("io.github.ngirchev.opendaimon.common.storage")) { + return SliceIdentifier.of("storage"); + } + return SliceIdentifier.ignore(); + } + + @Override + public String getDescription() { + return "common runtime slices"; + } + }; + + @ArchTest + static final ArchRule common_module_uses_no_service_or_component_stereotypes = + noClasses() + .that().resideInAnyPackage(COMMON_MODULE_PACKAGES) + .should().beAnnotatedWith(Service.class) + .orShould().beAnnotatedWith(Component.class) + .because("common exports Spring beans through explicit auto-configuration."); + + @ArchTest + static final ArchRule common_module_uses_no_repository_classes = + noClasses() + .that().resideInAnyPackage(COMMON_MODULE_PACKAGES) + .and().areNotInterfaces() + .should().beAnnotatedWith(Repository.class) + .because("@Repository is only allowed on Spring Data repository interfaces."); + + @ArchTest + static final ArchRule common_module_defines_no_delivery_controllers = + noClasses() + .that().resideInAnyPackage(COMMON_MODULE_PACKAGES) + .should().beAnnotatedWith(Controller.class) + .orShould().beAnnotatedWith(RestController.class) + .orShould().beAnnotatedWith(ControllerAdvice.class) + .because("common is a base library, not a delivery module."); + + @ArchTest + static final ArchRule common_module_does_not_depend_on_downstream_modules = + noClasses() + .that().resideInAnyPackage(COMMON_MODULE_PACKAGES) + .should().dependOnClassesThat().resideInAnyPackage(DOWNSTREAM_MODULE_PACKAGES) + .because("opendaimon-common is the base library and must not depend on delivery or AI modules."); + + @ArchTest + static final ArchRule common_runtime_slices_have_no_cycles = + slices().assignedFrom(COMMON_RUNTIME_SLICES) + .should().beFreeOfCycles() + .because("common package slices should stay independently understandable and reusable."); + + @ArchTest + static final ArchRule repositories_are_interfaces = + classes() + .that().resideInAnyPackage(COMMON_MODULE_PACKAGES) + .and().haveSimpleNameEndingWith("Repository") + .should().beInterfaces() + .because("common repositories are Spring Data interfaces, not concrete infrastructure classes."); + + @ArchTest + static final ArchRule bean_methods_are_declared_only_in_config_packages = + methods() + .that().areAnnotatedWith(Bean.class) + .should().beDeclaredInClassesThat().resideInAnyPackage(COMMON_CONFIG_PACKAGES) + .because("common beans must be exposed through explicit configuration classes."); + + @ArchTest + static final ArchRule configuration_classes_are_declared_only_in_config_packages = + classes() + .that().areAnnotatedWith(AutoConfiguration.class) + .or().areAnnotatedWith(Configuration.class) + .should().resideInAnyPackage(COMMON_CONFIG_PACKAGES) + .because("Spring configuration belongs in config packages."); + + @ArchTest + static final ArchRule configuration_properties_follow_common_conventions = + classes() + .that().areAnnotatedWith(ConfigurationProperties.class) + .should().resideInAnyPackage(COMMON_CONFIG_PACKAGES) + .andShould().haveSimpleNameEndingWith("Properties") + .andShould().beAnnotatedWith(Validated.class) + .andShould(HAVE_COMMON_CONFIGURATION_PREFIX) + .because("common configuration properties must stay validated and under open-daimon.common."); + + @ArchTest + static final ArchRule repositories_are_accessed_only_from_service_config_or_repositories = + noClasses() + .that().resideInAnyPackage(COMMON_MODULE_PACKAGES) + .and().resideOutsideOfPackages( + "io.github.ngirchev.opendaimon.common.config..", + "io.github.ngirchev.opendaimon.common.repository..", + "io.github.ngirchev.opendaimon.common.service..") + .should().dependOnClassesThat().resideInAPackage("io.github.ngirchev.opendaimon.common.repository..") + .because("repository access must stay behind services and explicit auto-configuration."); +} diff --git a/opendaimon-gateway-mock/pom.xml b/opendaimon-gateway-mock/pom.xml index ae9e1b98..b0b0b48c 100644 --- a/opendaimon-gateway-mock/pom.xml +++ b/opendaimon-gateway-mock/pom.xml @@ -40,45 +40,64 @@ ${project.version} - + - org.springframework.boot - spring-boot-starter + org.springframework + spring-context + org.springframework.boot - spring-boot-starter-validation + spring-boot - - - org.projectlombok - lombok - true + org.springframework.boot + spring-boot-autoconfigure - - - io.github.ngirchev - opendaimon-telegram - ${project.version} - test - + - org.springframework.boot - spring-boot-starter-data-jpa - test + jakarta.annotation + jakarta.annotation-api + + - org.springframework.boot - spring-boot-starter-test - test + org.slf4j + slf4j-api + + - com.h2database - h2 - test + org.projectlombok + lombok + provided + true + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-dependency-graph + + + + true + + org.springframework.boot:spring-boot-starter* + + + + + + + + + diff --git a/opendaimon-rest/pom.xml b/opendaimon-rest/pom.xml index 885ae2e6..79331371 100644 --- a/opendaimon-rest/pom.xml +++ b/opendaimon-rest/pom.xml @@ -37,42 +37,233 @@ ${project.version} + + + org.springframework + spring-context + + + org.springframework + spring-tx + + + org.springframework + spring-web + + + org.springframework.boot - spring-boot-starter-web + spring-boot + + + org.springframework.boot + spring-boot-autoconfigure + + + + + org.springframework.security + spring-security-config + + + org.springframework.security + spring-security-web + + + org.springframework.security + spring-security-core + + + + + org.springframework.data + spring-data-commons + + + org.springframework.data + spring-data-jpa + + + + + org.springframework.ai + spring-ai-model + + + + + io.projectreactor + reactor-core + + + org.reactivestreams + reactive-streams + + + + + org.apache.tomcat.embed + tomcat-embed-core - org.springframework.boot - spring-boot-starter-logging + org.apache.tomcat + tomcat-annotations-api + + - org.springframework.boot - spring-boot-starter-security + io.swagger.core.v3 + swagger-annotations-jakarta + + - org.springframework.boot - spring-boot-autoconfigure + jakarta.validation + jakarta.validation-api + + - org.springdoc - springdoc-openapi-starter-webmvc-ui + jakarta.persistence + jakarta.persistence-api + + + + jakarta.annotation + jakarta.annotation-api + + + org.flywaydb flyway-core + + + + org.slf4j + slf4j-api + + + org.projectlombok lombok + provided + true - + + + com.fasterxml.jackson.core + jackson-databind + + + + + org.springframework + spring-test + test + + + org.springframework + spring-webmvc + test + org.springframework.boot - spring-boot-starter-test + spring-boot-test-autoconfigure + test + + + com.jayway.jsonpath + json-path + test + + + org.junit.jupiter + junit-jupiter-api + test + + + com.tngtech.archunit + archunit + ${archunit.version} + test + + + com.tngtech.archunit + archunit-junit5-api + ${archunit.version} + test + + + com.tngtech.archunit + archunit-junit5-engine + ${archunit.version} + test + + + org.mockito + mockito-core + test + + + org.mockito + mockito-junit-jupiter + test + + + org.assertj + assertj-core + test + + + org.hamcrest + hamcrest test - \ No newline at end of file + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + org.springframework:spring-webmvc + com.jayway.jsonpath:json-path + + com.tngtech.archunit:archunit-junit5-engine + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + + true + + org.springframework.boot:spring-boot-starter* + + + + + + + + diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/repository/AdminConversationRepository.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/repository/AdminConversationRepository.java index 778a35c8..7868e739 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/repository/AdminConversationRepository.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/repository/AdminConversationRepository.java @@ -7,7 +7,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; /** * Admin-scope queries over ConversationThread. @@ -15,7 +14,6 @@ * core common contract — this keeps opendaimon-common untouched while still reusing * the ConversationThread entity. */ -@Repository public interface AdminConversationRepository extends JpaRepository { /** diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/repository/AdminUserRepository.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/repository/AdminUserRepository.java index 9b060ce5..32ae9743 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/repository/AdminUserRepository.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/repository/AdminUserRepository.java @@ -6,13 +6,11 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; /** * Polymorphic lookup over the base User table for admin filter dropdowns. * Returns TelegramUser / RestUser subclasses transparently thanks to JOINED inheritance. */ -@Repository public interface AdminUserRepository extends JpaRepository { /** diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/repository/RestUserRepository.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/repository/RestUserRepository.java index 10270b91..4acdee62 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/repository/RestUserRepository.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/repository/RestUserRepository.java @@ -1,12 +1,10 @@ package io.github.ngirchev.opendaimon.rest.repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; import io.github.ngirchev.opendaimon.rest.model.RestUser; import java.util.Optional; -@Repository public interface RestUserRepository extends JpaRepository { Optional findByEmail(String email); diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/RestUserService.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/RestUserService.java index 9b1405ea..512079e7 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/RestUserService.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/RestUserService.java @@ -83,23 +83,21 @@ public static void applyFlagsByLevel(RestUser user, UserPriority level) { if (level == null) { return; } - switch (level) { - case ADMIN -> { - user.setIsAdmin(true); - user.setIsPremium(true); - user.setIsBlocked(false); - } - case VIP -> { - user.setIsAdmin(false); - user.setIsPremium(true); - user.setIsBlocked(false); - } - case REGULAR, BLOCKED -> { - user.setIsAdmin(false); - user.setIsPremium(false); - user.setIsBlocked(level == UserPriority.BLOCKED); - } + if (level == UserPriority.ADMIN) { + user.setIsAdmin(true); + user.setIsPremium(true); + user.setIsBlocked(false); + return; } + if (level == UserPriority.VIP) { + user.setIsAdmin(false); + user.setIsPremium(true); + user.setIsBlocked(false); + return; + } + user.setIsAdmin(false); + user.setIsPremium(false); + user.setIsBlocked(level == UserPriority.BLOCKED); } /** @@ -186,4 +184,3 @@ public Optional findById(Long id) { return restUserRepository.findById(id); } } - diff --git a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/arch/RestArchitectureTest.java b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/arch/RestArchitectureTest.java new file mode 100644 index 00000000..b6acf0e7 --- /dev/null +++ b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/arch/RestArchitectureTest.java @@ -0,0 +1,185 @@ +package io.github.ngirchev.opendaimon.rest.arch; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.methods; +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; + +import com.tngtech.archunit.core.domain.Dependency; +import com.tngtech.archunit.core.domain.JavaClass; +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.junit.AnalyzeClasses; +import com.tngtech.archunit.junit.ArchTest; +import com.tngtech.archunit.lang.ArchCondition; +import com.tngtech.archunit.lang.ArchRule; +import com.tngtech.archunit.lang.ConditionEvents; +import com.tngtech.archunit.lang.SimpleConditionEvent; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.Set; + +@AnalyzeClasses( + packages = "io.github.ngirchev.opendaimon.rest", + importOptions = { + ImportOption.DoNotIncludeTests.class, + ImportOption.DoNotIncludeJars.class + } +) +class RestArchitectureTest { + + private static final String REST_PACKAGE = "io.github.ngirchev.opendaimon.rest"; + private static final String REST_MODULE_PACKAGE = REST_PACKAGE + ".."; + private static final String REST_CONFIG_PACKAGE = REST_PACKAGE + ".config.."; + private static final String REST_CONTROLLER_PACKAGE = REST_PACKAGE + ".controller.."; + private static final String REST_DTO_PACKAGE = REST_PACKAGE + ".dto.."; + private static final String REST_HANDLER_PACKAGE = REST_PACKAGE + ".handler.."; + private static final String REST_MODEL_PACKAGE = REST_PACKAGE + ".model.."; + private static final String REST_REPOSITORY_PACKAGE = REST_PACKAGE + ".repository.."; + private static final String REST_SERVICE_PACKAGE = REST_PACKAGE + ".service.."; + + private static final String REST_CONTROLLER_PACKAGE_PREFIX = REST_PACKAGE + ".controller"; + private static final String REST_HANDLER_PACKAGE_PREFIX = REST_PACKAGE + ".handler"; + + private static final String CHAT_SERVICE = REST_PACKAGE + ".service.ChatService"; + private static final Set CHAT_SERVICE_COMMAND_BRIDGE_TYPES = Set.of( + REST_PACKAGE + ".handler.RestChatCommand", + REST_PACKAGE + ".handler.RestChatCommandType" + ); + + private static final ArchCondition HAVE_REST_CONFIGURATION_PREFIX = + new ArchCondition<>("have an open-daimon.rest configuration prefix") { + @Override + public void check(JavaClass item, ConditionEvents events) { + ConfigurationProperties annotation = item.getAnnotationOfType(ConfigurationProperties.class); + String prefix = annotation.prefix().isBlank() ? annotation.value() : annotation.prefix(); + if (!prefix.startsWith("open-daimon.rest")) { + events.add(SimpleConditionEvent.violated( + item, + item.getName() + " uses configuration prefix '" + prefix + "'")); + } + } + }; + + private static final ArchCondition HAVE_NO_REST_DELIVERY_DEPENDENCIES_EXCEPT_COMMAND_BRIDGE = + new ArchCondition<>("not depend on REST delivery classes except the ChatService command bridge") { + @Override + public void check(JavaClass item, ConditionEvents events) { + item.getDirectDependenciesFromSelf().stream() + .map(Dependency::getTargetClass) + .filter(RestArchitectureTest::isRestDeliveryClass) + .filter(targetClass -> !isAllowedCommandBridge(item, targetClass)) + .forEach(targetClass -> events.add(SimpleConditionEvent.violated( + item, + item.getName() + " depends on delivery class " + targetClass.getName()))); + } + }; + + @ArchTest + static final ArchRule rest_module_uses_no_service_or_component_stereotypes = + noClasses() + .that().resideInAPackage(REST_MODULE_PACKAGE) + .should().beAnnotatedWith(Service.class) + .orShould().beAnnotatedWith(Component.class) + .because("REST starter beans must be exposed through explicit auto-configuration."); + + @ArchTest + static final ArchRule rest_module_uses_no_repository_classes = + noClasses() + .that().resideInAPackage(REST_MODULE_PACKAGE) + .and().areNotInterfaces() + .should().beAnnotatedWith(Repository.class) + .because("@Repository is only allowed on Spring Data repository interfaces."); + + @ArchTest + static final ArchRule bean_methods_are_declared_only_in_config_package = + methods() + .that().areAnnotatedWith(Bean.class) + .should().beDeclaredInClassesThat().resideInAPackage(REST_CONFIG_PACKAGE) + .because("REST beans must be exposed through explicit configuration classes."); + + @ArchTest + static final ArchRule configuration_classes_are_declared_only_in_config_package = + classes() + .that().areAnnotatedWith(AutoConfiguration.class) + .or().areAnnotatedWith(Configuration.class) + .should().resideInAPackage(REST_CONFIG_PACKAGE) + .because("REST Spring configuration belongs in the config package."); + + @ArchTest + static final ArchRule configuration_properties_follow_rest_conventions = + classes() + .that().areAnnotatedWith(ConfigurationProperties.class) + .should().resideInAPackage(REST_CONFIG_PACKAGE) + .andShould().haveSimpleNameEndingWith("Properties") + .andShould().beAnnotatedWith(Validated.class) + .andShould(HAVE_REST_CONFIGURATION_PREFIX) + .because("REST configuration properties must stay validated and under open-daimon.rest."); + + @ArchTest + static final ArchRule repositories_are_interfaces = + classes() + .that().resideInAPackage(REST_REPOSITORY_PACKAGE) + .and().haveSimpleNameEndingWith("Repository") + .should().beInterfaces() + .because("REST repositories are Spring Data interfaces, not concrete infrastructure classes."); + + @ArchTest + static final ArchRule repositories_are_accessed_only_from_service_config_or_repositories = + noClasses() + .that().resideInAPackage(REST_MODULE_PACKAGE) + .and().resideOutsideOfPackages( + REST_CONFIG_PACKAGE, + REST_REPOSITORY_PACKAGE, + REST_SERVICE_PACKAGE) + .should().dependOnClassesThat().resideInAnyPackage( + "io.github.ngirchev.opendaimon.common.repository..", + REST_REPOSITORY_PACKAGE) + .because("repository access must stay behind services and explicit auto-configuration."); + + @ArchTest + static final ArchRule controllers_do_not_depend_on_repositories_or_handlers = + noClasses() + .that().resideInAPackage(REST_CONTROLLER_PACKAGE) + .should().dependOnClassesThat().resideInAnyPackage( + REST_HANDLER_PACKAGE, + REST_REPOSITORY_PACKAGE) + .because("REST controllers should delegate to services instead of handlers or repositories."); + + @ArchTest + static final ArchRule dto_and_model_are_passive = + noClasses() + .that().resideInAnyPackage( + REST_DTO_PACKAGE, + REST_MODEL_PACKAGE) + .should().dependOnClassesThat().resideInAnyPackage( + REST_CONFIG_PACKAGE, + REST_CONTROLLER_PACKAGE, + REST_HANDLER_PACKAGE, + REST_REPOSITORY_PACKAGE, + REST_SERVICE_PACKAGE) + .because("REST DTO and model classes must not know about runtime layers."); + + @ArchTest + static final ArchRule services_do_not_depend_on_delivery_layers_except_command_bridge = + classes() + .that().resideInAPackage(REST_SERVICE_PACKAGE) + .should(HAVE_NO_REST_DELIVERY_DEPENDENCIES_EXCEPT_COMMAND_BRIDGE) + .because("REST services should stay behind delivery layers; ChatService keeps the current public command bridge."); + + private static boolean isRestDeliveryClass(JavaClass javaClass) { + String packageName = javaClass.getPackageName(); + return packageName.startsWith(REST_CONTROLLER_PACKAGE_PREFIX) + || packageName.startsWith(REST_HANDLER_PACKAGE_PREFIX); + } + + private static boolean isAllowedCommandBridge(JavaClass item, JavaClass targetClass) { + return item.getName().equals(CHAT_SERVICE) + && CHAT_SERVICE_COMMAND_BRIDGE_TYPES.contains(targetClass.getName()); + } +} diff --git a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/controller/SessionControllerContractTest.java b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/controller/SessionControllerContractTest.java index 7f854baa..cb416ea7 100644 --- a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/controller/SessionControllerContractTest.java +++ b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/controller/SessionControllerContractTest.java @@ -16,11 +16,11 @@ import io.github.ngirchev.opendaimon.rest.repository.RestUserRepository; import io.github.ngirchev.opendaimon.rest.service.ChatService; import io.github.ngirchev.opendaimon.rest.service.RestAuthorizationService; +import jakarta.annotation.Resource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; @@ -33,6 +33,7 @@ import java.time.OffsetDateTime; import java.util.List; +import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; @@ -60,10 +61,10 @@ class SessionControllerContractTest { private static final String TEST_EMAIL = "user@test.com"; private static final String SESSION_ID = "session-123"; - @Autowired + @Resource private MockMvc mockMvc; - @Autowired + @Resource private ObjectMapper objectMapper; @MockitoBean @@ -110,8 +111,8 @@ void whenAuthorized_returns200AndResponseDto() throws Exception { .content(toJson(request))) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.message").value("AI reply")) - .andExpect(jsonPath("$.sessionId").value(SESSION_ID)); + .andExpect(jsonPath("$.message").value(equalTo("AI reply"))) + .andExpect(jsonPath("$.sessionId").value(equalTo(SESSION_ID))); } @Test @@ -126,8 +127,8 @@ void whenNoEmail_returns401() throws Exception { .andExpect(status().isUnauthorized()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.message").exists()) - .andExpect(jsonPath("$.status").value(401)) - .andExpect(jsonPath("$.redirect").value("/login")); + .andExpect(jsonPath("$.status").value(equalTo(401))) + .andExpect(jsonPath("$.redirect").value(equalTo("/login"))); } @Test @@ -142,8 +143,8 @@ void whenAuthorizeThrows_returns401() throws Exception { .accept(MediaType.APPLICATION_JSON) .content(toJson(request))) .andExpect(status().isUnauthorized()) - .andExpect(jsonPath("$.message").value("User not found")) - .andExpect(jsonPath("$.status").value(401)); + .andExpect(jsonPath("$.message").value(equalTo("User not found"))) + .andExpect(jsonPath("$.status").value(equalTo(401))); } } @@ -165,8 +166,8 @@ void whenAuthorized_returns200AndResponseDto() throws Exception { .content(toJson(request))) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.message").value("AI reply")) - .andExpect(jsonPath("$.sessionId").value(SESSION_ID)); + .andExpect(jsonPath("$.message").value(equalTo("AI reply"))) + .andExpect(jsonPath("$.sessionId").value(equalTo(SESSION_ID))); } @Test @@ -199,11 +200,11 @@ void whenAuthorized_returns200AndSessionList() throws Exception { mockMvc.perform(get(BASE_URL).param("email", TEST_EMAIL)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.length()").value(2)) - .andExpect(jsonPath("$[0].sessionId").value("s1")) - .andExpect(jsonPath("$[0].name").value("Chat 1")) + .andExpect(jsonPath("$.length()").value(equalTo(2))) + .andExpect(jsonPath("$[0].sessionId").value(equalTo("s1"))) + .andExpect(jsonPath("$[0].name").value(equalTo("Chat 1"))) .andExpect(jsonPath("$[0].createdAt").exists()) - .andExpect(jsonPath("$[1].sessionId").value("s2")); + .andExpect(jsonPath("$[1].sessionId").value(equalTo("s2"))); } @Test @@ -231,12 +232,12 @@ void whenAuthorized_returns200AndHistory() throws Exception { mockMvc.perform(get(BASE_URL + "/" + SESSION_ID + "/messages").param("email", TEST_EMAIL)) .andExpect(status().isOk()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect(jsonPath("$.sessionId").value(SESSION_ID)) - .andExpect(jsonPath("$.messages.length()").value(2)) - .andExpect(jsonPath("$.messages[0].role").value("USER")) - .andExpect(jsonPath("$.messages[0].content").value("Hello")) - .andExpect(jsonPath("$.messages[1].role").value("ASSISTANT")) - .andExpect(jsonPath("$.messages[1].content").value("Hi there")); + .andExpect(jsonPath("$.sessionId").value(equalTo(SESSION_ID))) + .andExpect(jsonPath("$.messages.length()").value(equalTo(2))) + .andExpect(jsonPath("$.messages[0].role").value(equalTo("USER"))) + .andExpect(jsonPath("$.messages[0].content").value(equalTo("Hello"))) + .andExpect(jsonPath("$.messages[1].role").value(equalTo("ASSISTANT"))) + .andExpect(jsonPath("$.messages[1].content").value(equalTo("Hi there"))); } @Test @@ -291,7 +292,7 @@ void whenJsonAccept_returns400Json() throws Exception { .andExpect(status().isBadRequest()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.message").exists()) - .andExpect(jsonPath("$.status").value(400)); + .andExpect(jsonPath("$.status").value(equalTo(400))); } } @@ -315,7 +316,7 @@ void whenJsonAccept_returns403Json() throws Exception { .andExpect(status().isForbidden()) .andExpect(content().contentType(MediaType.APPLICATION_JSON)) .andExpect(jsonPath("$.message").exists()) - .andExpect(jsonPath("$.status").value(403)); + .andExpect(jsonPath("$.status").value(equalTo(403))); } } diff --git a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatHandlerSupportTest.java b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatHandlerSupportTest.java index d4f155d8..464acd46 100644 --- a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatHandlerSupportTest.java +++ b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatHandlerSupportTest.java @@ -1,6 +1,5 @@ package io.github.ngirchev.opendaimon.rest.handler; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import io.github.ngirchev.opendaimon.common.SupportedLanguages; import io.github.ngirchev.opendaimon.common.ai.ModelCapabilities; @@ -119,7 +118,7 @@ void containsModelErrorTypeErrorMessageAndTimestamp() { class SerializeToJson { @Test - void whenMapValid_returnsJsonString() throws JsonProcessingException { + void whenMapValid_returnsJsonString() throws Exception { Map map = Map.of("key", "value"); when(objectMapper.writeValueAsString(map)).thenReturn("{\"key\":\"value\"}"); @@ -137,7 +136,7 @@ void whenMapEmpty_returnsNull() { } @Test - void whenWriteValueThrows_returnsNull() throws JsonProcessingException { + void whenWriteValueThrows_returnsNull() throws Exception { Map map = Map.of("x", "y"); when(objectMapper.writeValueAsString(map)).thenThrow(new RuntimeException("serialization failed")); @@ -150,7 +149,7 @@ void whenWriteValueThrows_returnsNull() throws JsonProcessingException { class HandleProcessingError { @Test - void whenUserMessageNotNull_savesAssistantErrorMessageAndReturnsRuntimeException() throws JsonProcessingException { + void whenUserMessageNotNull_savesAssistantErrorMessageAndReturnsRuntimeException() throws Exception { HttpServletRequest request = mockRequestWithLocale(Locale.ENGLISH); RestChatCommand command = new RestChatCommand(new ChatRequestDto("hi", null, null, null), RestChatCommandType.MESSAGE, request, 1L); RestUser user = new RestUser(); @@ -181,7 +180,7 @@ void whenUserMessageNull_doesNotCallSaveAssistantErrorMessage() { } @Test - void whenModelCapabilitiesEmpty_usesChatInMetadata() throws JsonProcessingException { + void whenModelCapabilitiesEmpty_usesChatInMetadata() throws Exception { when(objectMapper.writeValueAsString(any())).thenAnswer(inv -> { @SuppressWarnings("unchecked") Map m = inv.getArgument(0); diff --git a/opendaimon-spring-ai/pom.xml b/opendaimon-spring-ai/pom.xml index 85c186d0..1fc9a87f 100644 --- a/opendaimon-spring-ai/pom.xml +++ b/opendaimon-spring-ai/pom.xml @@ -27,8 +27,6 @@ UTF-8 UTF-8 - 1.17.2 - 3.0.5 @@ -38,99 +36,237 @@ opendaimon-common ${project.version} + + io.github.ngirchev + fsm + - + - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-logging - - + org.springframework + spring-core + + + org.springframework + spring-beans + + + org.springframework + spring-context + + + org.springframework + spring-tx + + + org.springframework + spring-web + + + org.springframework + spring-webflux + org.springframework.boot - spring-boot-starter-validation + spring-boot + + + org.springframework.boot + spring-boot-autoconfigure org.springframework.ai - spring-ai-starter-model-ollama + spring-ai-model + + + org.springframework.ai + spring-ai-client-chat + + + org.springframework.ai + spring-ai-commons + + + org.springframework.ai + spring-ai-ollama org.springframework.ai - spring-ai-starter-model-openai + spring-ai-openai + org.springframework.ai - spring-ai-starter-model-chat-memory + spring-ai-autoconfigure-model-chat-memory + runtime org.springframework.ai - spring-ai-starter-model-chat-memory-repository-jdbc + spring-ai-autoconfigure-model-chat-memory-repository-jdbc + runtime - + org.springframework.ai spring-ai-pdf-document-reader - org.springframework.ai spring-ai-tika-document-reader + + + commons-logging + commons-logging + + - org.springframework.ai spring-ai-vector-store - + + + io.projectreactor + reactor-core + + + org.reactivestreams + reactive-streams + + + + io.netty + netty-resolver + + + io.netty + netty-handler + + + io.projectreactor.netty + reactor-netty-http + + + io.projectreactor.netty + reactor-netty-core + + + + + org.aspectj + aspectjweaver + + + + + jakarta.validation + jakarta.validation-api + + + + + org.apache.tika + tika-core + + + org.apache.pdfbox pdfbox - ${pdfbox.version} org.apache.pdfbox pdfbox-io - ${pdfbox.version} + + + commons-logging + commons-logging + + + + + + + jakarta.persistence + jakarta.persistence-api + + + + + org.flywaydb + flyway-core + + + + + jakarta.annotation + jakarta.annotation-api + + + org.jetbrains + annotations + + + + + org.slf4j + slf4j-api + org.projectlombok lombok + provided true - + - org.springframework.boot - spring-boot-starter-webflux + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.core + jackson-core - + org.jsoup jsoup - ${jsoup.version} - + com.github.ben-manes.caffeine caffeine - ${caffeine.version} + + org.springframework + spring-test + test + org.springframework.boot - spring-boot-starter-test + spring-boot-test + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.mockito + mockito-core test @@ -139,8 +275,13 @@ test - com.h2database - h2 + org.assertj + assertj-core + test + + + com.squareup.okhttp3 + okhttp test @@ -149,4 +290,48 @@ test + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + org.apache.pdfbox:pdfbox-io + + org.springframework.ai:spring-ai-autoconfigure-model-chat-memory + org.springframework.ai:spring-ai-autoconfigure-model-chat-memory-repository-jdbc + + + + jakarta.persistence:jakarta.persistence-api + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + + true + + org.springframework.boot:spring-boot-starter* + + + + + + + diff --git a/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/config/SpringAIAutoConfig.java b/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/config/SpringAIAutoConfig.java index 5d02ff02..49607a54 100644 --- a/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/config/SpringAIAutoConfig.java +++ b/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/config/SpringAIAutoConfig.java @@ -66,8 +66,6 @@ import org.springframework.context.support.GenericApplicationContext; import java.util.List; -import io.github.ngirchev.opendaimon.common.repository.OpenDaimonMessageRepository; -import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; import io.github.ngirchev.opendaimon.ai.springai.retry.OpenRouterFreeModelResolver; import io.github.ngirchev.opendaimon.ai.springai.retry.OpenRouterModelsApiClient; import io.github.ngirchev.opendaimon.ai.springai.retry.OpenRouterModelsProperties; @@ -75,6 +73,8 @@ import io.github.ngirchev.opendaimon.ai.springai.retry.metrics.OpenRouterStreamMetricsTracker; import io.github.ngirchev.opendaimon.common.ai.ModelDescriptionCache; import io.github.ngirchev.opendaimon.common.service.AIGatewayRegistry; +import io.github.ngirchev.opendaimon.common.service.ConversationThreadService; +import io.github.ngirchev.opendaimon.common.service.OpenDaimonMessageService; import io.github.ngirchev.opendaimon.common.service.SummarizationService; @Slf4j @@ -508,16 +508,16 @@ public UrlLivenessChecker urlLivenessChecker( @DependsOn("springAiFlyway") public ChatMemory chatMemoryOnPostgresDb( ChatMemoryRepository chatMemoryRepository, - ConversationThreadRepository conversationThreadRepository, - OpenDaimonMessageRepository messageRepository, + ConversationThreadService conversationThreadService, + OpenDaimonMessageService messageService, SummarizationService summarizationService, org.springframework.context.ApplicationEventPublisher eventPublisher, CoreCommonProperties coreCommonProperties) { return new SummarizingChatMemory( chatMemoryRepository, - conversationThreadRepository, - messageRepository, + conversationThreadService, + messageService, summarizationService, eventPublisher, coreCommonProperties.getSummarization().getMessageWindowSize(), diff --git a/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/memory/SummarizingChatMemory.java b/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/memory/SummarizingChatMemory.java index 18a92ba1..4ca6f5e5 100644 --- a/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/memory/SummarizingChatMemory.java +++ b/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/memory/SummarizingChatMemory.java @@ -15,8 +15,8 @@ import io.github.ngirchev.opendaimon.common.model.ConversationThread; import io.github.ngirchev.opendaimon.common.model.MessageRole; import io.github.ngirchev.opendaimon.common.model.OpenDaimonMessage; -import io.github.ngirchev.opendaimon.common.repository.OpenDaimonMessageRepository; -import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; +import io.github.ngirchev.opendaimon.common.service.ConversationThreadService; +import io.github.ngirchev.opendaimon.common.service.OpenDaimonMessageService; import io.github.ngirchev.opendaimon.common.service.SummarizationService; import java.util.ArrayList; @@ -39,8 +39,8 @@ public class SummarizingChatMemory implements ChatMemory { private final MessageWindowChatMemory delegate; // MessageWindowChatMemory - private final ConversationThreadRepository conversationThreadRepository; - private final OpenDaimonMessageRepository messageRepository; + private final ConversationThreadService conversationThreadService; + private final OpenDaimonMessageService messageService; private final SummarizationService summarizationService; private final ApplicationEventPublisher eventPublisher; private final Integer maxMessages; // Max messages from MessageWindowChatMemory @@ -64,14 +64,14 @@ public class SummarizingChatMemory implements ChatMemory { public SummarizingChatMemory( ChatMemoryRepository chatMemoryRepository, - ConversationThreadRepository conversationThreadRepository, - OpenDaimonMessageRepository messageRepository, + ConversationThreadService conversationThreadService, + OpenDaimonMessageService messageService, SummarizationService summarizationService, ApplicationEventPublisher eventPublisher, Integer maxMessages, Integer maxWindowTokens) { - this.conversationThreadRepository = conversationThreadRepository; - this.messageRepository = messageRepository; + this.conversationThreadService = conversationThreadService; + this.messageService = messageService; this.summarizationService = summarizationService; this.eventPublisher = eventPublisher; this.maxMessages = maxMessages; @@ -117,7 +117,7 @@ public List get(@NonNull String conversationId) { boolean tokenLimitReached = false; if (!messageLimitReached && maxWindowTokens != null) { - Optional threadOpt = conversationThreadRepository.findByThreadKey(conversationId); + Optional threadOpt = conversationThreadService.findByThreadKey(conversationId); tokenLimitReached = threadOpt .map(t -> t.getTotalTokens() != null && t.getTotalTokens() >= maxWindowTokens) .orElse(false); @@ -170,7 +170,7 @@ public void add(@NonNull String conversationId, @NonNull List messages) private List restoreHistoryFromPrimaryStore(@NonNull String conversationId) { try { Optional threadOpt = - conversationThreadRepository.findByThreadKey(conversationId); + conversationThreadService.findByThreadKey(conversationId); if (threadOpt.isEmpty()) { return List.of(); } @@ -184,7 +184,7 @@ private List restoreHistoryFromPrimaryStore(@NonNull String conversatio Integer messagesAtLastSummarization = thread.getMessagesAtLastSummarization(); int minSequenceNumber = messagesAtLastSummarization != null ? messagesAtLastSummarization : 0; - List postSummaryMessages = messageRepository + List postSummaryMessages = messageService .findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(thread, minSequenceNumber); // Drop the trailing in-flight USER row: TelegramMessageHandlerActions.saveMessage @@ -235,7 +235,7 @@ private List restoreHistoryFromPrimaryStore(@NonNull String conversatio */ private boolean performSummarizationAndUpdateChatMemory(@NonNull String conversationId) { try { - Optional threadOpt = conversationThreadRepository.findByThreadKey(conversationId); + Optional threadOpt = conversationThreadService.findByThreadKey(conversationId); if (threadOpt.isEmpty()) { log.debug("Thread not found for conversationId {}, skipping summarization", conversationId); @@ -251,7 +251,7 @@ private boolean performSummarizationAndUpdateChatMemory(@NonNull String conversa Integer messagesAtLastSummarization = thread.getMessagesAtLastSummarization(); int minSequenceNumber = messagesAtLastSummarization != null ? messagesAtLastSummarization : 0; - List allMessages = new ArrayList<>(messageRepository + List allMessages = new ArrayList<>(messageService .findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(thread, minSequenceNumber)); if (allMessages.size() < 2) { @@ -271,7 +271,7 @@ private boolean performSummarizationAndUpdateChatMemory(@NonNull String conversa summarizationService.summarizeThread(thread, toSummarize); // Refresh thread from DB after summarization - thread = conversationThreadRepository.findByThreadKey(conversationId) + thread = conversationThreadService.findByThreadKey(conversationId) .orElseThrow(() -> new RuntimeException("Thread not found after summarization")); // Rebuild ChatMemory atomically so that any concurrent get() on the same diff --git a/opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/memory/SummarizingChatMemoryTest.java b/opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/memory/SummarizingChatMemoryTest.java index b58fda18..ce77423a 100644 --- a/opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/memory/SummarizingChatMemoryTest.java +++ b/opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/memory/SummarizingChatMemoryTest.java @@ -3,8 +3,8 @@ import io.github.ngirchev.opendaimon.common.model.MessageRole; import io.github.ngirchev.opendaimon.common.model.OpenDaimonMessage; import io.github.ngirchev.opendaimon.common.model.ConversationThread; -import io.github.ngirchev.opendaimon.common.repository.OpenDaimonMessageRepository; -import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; +import io.github.ngirchev.opendaimon.common.service.ConversationThreadService; +import io.github.ngirchev.opendaimon.common.service.OpenDaimonMessageService; import io.github.ngirchev.opendaimon.common.service.SummarizationService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -56,9 +56,9 @@ class SummarizingChatMemoryTest { private SummarizingChatMemory summarizingChatMemory; @Mock - private ConversationThreadRepository conversationThreadRepository; + private ConversationThreadService conversationThreadService; @Mock - private OpenDaimonMessageRepository messageRepository; + private OpenDaimonMessageService messageService; @Mock private SummarizationService summarizationService; @Mock @@ -69,8 +69,8 @@ void setUp() { ChatMemoryRepository chatMemoryRepository = new InMemoryChatMemoryRepository(); summarizingChatMemory = new SummarizingChatMemory( chatMemoryRepository, - conversationThreadRepository, - messageRepository, + conversationThreadService, + messageService, summarizationService, eventPublisher, MAX_MESSAGES, @@ -82,12 +82,12 @@ void setUp() { void whenGetWithFewerThanMaxMessages_thenReturnsMessagesWithoutSummarization() { summarizingChatMemory.add(CONVERSATION_ID, new UserMessage("Hello")); summarizingChatMemory.add(CONVERSATION_ID, new AssistantMessage("Hi")); - when(conversationThreadRepository.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.empty()); + when(conversationThreadService.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.empty()); List result = summarizingChatMemory.get(CONVERSATION_ID); assertEquals(2, result.size()); - verify(conversationThreadRepository, times(1)).findByThreadKey(CONVERSATION_ID); + verify(conversationThreadService, times(1)).findByThreadKey(CONVERSATION_ID); verify(summarizationService, never()).summarizeThread(any(), any()); } @@ -129,11 +129,11 @@ void whenGetWithMessageCountAtMax_thenSummarizationTriggered() { for (int i = 0; i < MAX_MESSAGES; i++) { summarizingChatMemory.add(CONVERSATION_ID, new UserMessage("u" + i)); } - when(conversationThreadRepository.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.empty()); + when(conversationThreadService.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.empty()); summarizingChatMemory.get(CONVERSATION_ID); - verify(conversationThreadRepository).findByThreadKey(CONVERSATION_ID); + verify(conversationThreadService).findByThreadKey(CONVERSATION_ID); } @Test @@ -142,11 +142,11 @@ void whenGetWithMessageCountBelowMax_thenSummarizationNotTriggered() { for (int i = 0; i < MAX_MESSAGES - 1; i++) { summarizingChatMemory.add(CONVERSATION_ID, new UserMessage("u" + i)); } - when(conversationThreadRepository.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.empty()); + when(conversationThreadService.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.empty()); summarizingChatMemory.get(CONVERSATION_ID); - verify(conversationThreadRepository, times(1)).findByThreadKey(CONVERSATION_ID); + verify(conversationThreadService, times(1)).findByThreadKey(CONVERSATION_ID); verify(summarizationService, never()).summarizeThread(any(), any()); } @@ -156,13 +156,13 @@ void whenGetWithMessageCountAtMaxAndThreadNotFound_thenReturnsDelegateMessagesWi summarizingChatMemory.add(CONVERSATION_ID, new UserMessage("u" + i)); summarizingChatMemory.add(CONVERSATION_ID, new AssistantMessage("a" + i)); } - when(conversationThreadRepository.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.empty()); + when(conversationThreadService.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.empty()); List result = summarizingChatMemory.get(CONVERSATION_ID); // Delegate (MessageWindowChatMemory) keeps only last maxMessages messages assertEquals(MAX_MESSAGES, result.size()); - verify(conversationThreadRepository).findByThreadKey(CONVERSATION_ID); + verify(conversationThreadService).findByThreadKey(CONVERSATION_ID); verify(summarizationService, never()).summarizeThread(any(), any()); } @@ -174,14 +174,14 @@ void whenGetWithMessageCountAtMaxAndThreadFoundButOnlyOneMessageInDb_thenSummari } ConversationThread thread = new ConversationThread(); thread.setThreadKey(CONVERSATION_ID); - when(conversationThreadRepository.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.of(thread)); + when(conversationThreadService.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.of(thread)); // One message: size < 2, partial summarization is skipped - when(messageRepository.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(eq(thread), any())) + when(messageService.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(eq(thread), any())) .thenReturn(new ArrayList<>(List.of(createMockMessage(MessageRole.USER)))); List result = summarizingChatMemory.get(CONVERSATION_ID); - verify(conversationThreadRepository, atLeastOnce()).findByThreadKey(CONVERSATION_ID); + verify(conversationThreadService, atLeastOnce()).findByThreadKey(CONVERSATION_ID); verify(summarizationService, never()).summarizeThread(any(), any()); } @@ -199,7 +199,7 @@ void whenGetWithMessageCountAtMaxAndSummarizationSucceeds_thenChatMemoryContains threadWithSummary.setSummary("Previous talk summary"); threadWithSummary.setMemoryBullets(List.of("Point one", "Point two")); - when(conversationThreadRepository.findByThreadKey(CONVERSATION_ID)) + when(conversationThreadService.findByThreadKey(CONVERSATION_ID)) .thenReturn(Optional.of(thread)) .thenReturn(Optional.of(threadWithSummary)); // 4 messages in DB: partial summarization splits into 2 to summarize + 2 to keep @@ -208,7 +208,7 @@ void whenGetWithMessageCountAtMaxAndSummarizationSucceeds_thenChatMemoryContains createMockMessage(MessageRole.ASSISTANT), createMockMessage(MessageRole.USER), createMockMessage(MessageRole.ASSISTANT))); - when(messageRepository.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(eq(thread), any())) + when(messageService.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(eq(thread), any())) .thenReturn(dbMessages); List result = summarizingChatMemory.get(CONVERSATION_ID); @@ -242,7 +242,7 @@ void whenGetWithMessageCountAtMaxAndSummarizationReturnsEmptySummary_thenNoSumma threadAfterSummary.setThreadKey(CONVERSATION_ID); threadAfterSummary.setSummary(null); - when(conversationThreadRepository.findByThreadKey(CONVERSATION_ID)) + when(conversationThreadService.findByThreadKey(CONVERSATION_ID)) .thenReturn(Optional.of(thread)) .thenReturn(Optional.of(threadAfterSummary)); ArrayList dbMessages = new ArrayList<>(List.of( @@ -250,7 +250,7 @@ void whenGetWithMessageCountAtMaxAndSummarizationReturnsEmptySummary_thenNoSumma createMockMessage(MessageRole.ASSISTANT), createMockMessage(MessageRole.USER), createMockMessage(MessageRole.ASSISTANT))); - when(messageRepository.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(eq(thread), any())) + when(messageService.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(eq(thread), any())) .thenReturn(dbMessages); List result = summarizingChatMemory.get(CONVERSATION_ID); @@ -272,8 +272,8 @@ void whenSummarizationServiceThrows_thenSummarizationFailedExceptionPropagates() } ConversationThread thread = new ConversationThread(); thread.setThreadKey(CONVERSATION_ID); - when(conversationThreadRepository.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.of(thread)); - when(messageRepository.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(eq(thread), any())) + when(conversationThreadService.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.of(thread)); + when(messageService.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(eq(thread), any())) .thenReturn(new ArrayList<>(List.of( createMockMessage(MessageRole.USER), createMockMessage(MessageRole.ASSISTANT), @@ -297,12 +297,12 @@ void whenTokenLimitReachedButMessagesBeforeLimit_thenSummarizationTriggeredByTok thread.setThreadKey(CONVERSATION_ID); thread.setTotalTokens((long) MAX_WINDOW_TOKENS); // At the limit - when(conversationThreadRepository.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.of(thread)); + when(conversationThreadService.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.of(thread)); summarizingChatMemory.get(CONVERSATION_ID); // Token check in get(), then load thread again in performSummarizationAndUpdateChatMemory - verify(conversationThreadRepository, times(2)).findByThreadKey(CONVERSATION_ID); + verify(conversationThreadService, times(2)).findByThreadKey(CONVERSATION_ID); } @Test @@ -316,12 +316,12 @@ void whenTokensBeforeLimitAndMessagesBeforeLimit_thenSummarizationNotTriggered() thread.setThreadKey(CONVERSATION_ID); thread.setTotalTokens(5000L); // Well below MAX_WINDOW_TOKENS=16000 - when(conversationThreadRepository.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.of(thread)); + when(conversationThreadService.findByThreadKey(CONVERSATION_ID)).thenReturn(Optional.of(thread)); summarizingChatMemory.get(CONVERSATION_ID); // Thread is loaded once to evaluate totalTokens vs maxWindowTokens - verify(conversationThreadRepository, times(1)).findByThreadKey(CONVERSATION_ID); + verify(conversationThreadService, times(1)).findByThreadKey(CONVERSATION_ID); verify(summarizationService, never()).summarizeThread(any(), any()); } @@ -338,10 +338,10 @@ void shouldDropTrailingInFlightUserMessageWhenRestoringFromPrimaryStore() { // Delegate is empty (fresh app start / eviction) — get() triggers primary-store restore. ConversationThread thread = new ConversationThread(); thread.setThreadKey(CONVERSATION_ID); - when(conversationThreadRepository.findByThreadKey(CONVERSATION_ID)) + when(conversationThreadService.findByThreadKey(CONVERSATION_ID)) .thenReturn(Optional.of(thread)); // Primary store: 3 ASSISTANT turns interleaved with USER, tail is an in-flight USER row. - when(messageRepository.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(eq(thread), any())) + when(messageService.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(eq(thread), any())) .thenReturn(new ArrayList<>(List.of( createMockMessage(MessageRole.USER, "u0"), createMockMessage(MessageRole.ASSISTANT, "a0"), @@ -371,14 +371,14 @@ void shouldDropTrailingInFlightUserMessageWhenRestoringFromPrimaryStore() { void shouldDropTrailingInFlightUserMessageWithAttachmentsEnrichment() { ConversationThread thread = new ConversationThread(); thread.setThreadKey(CONVERSATION_ID); - when(conversationThreadRepository.findByThreadKey(CONVERSATION_ID)) + when(conversationThreadService.findByThreadKey(CONVERSATION_ID)) .thenReturn(Optional.of(thread)); OpenDaimonMessage trailingUserWithAttachments = createMockMessage(MessageRole.USER, "describe this"); trailingUserWithAttachments.setAttachments(List.of( java.util.Map.of("type", "image", "name", "photo.jpg"))); - when(messageRepository.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(eq(thread), any())) + when(messageService.findByThreadAndSequenceNumberGreaterThanOrderBySequenceNumberAsc(eq(thread), any())) .thenReturn(new ArrayList<>(List.of( createMockMessage(MessageRole.USER, "earlier prompt"), createMockMessage(MessageRole.ASSISTANT, "earlier reply"), diff --git a/opendaimon-telegram/pom.xml b/opendaimon-telegram/pom.xml index d0aed65e..81cf6337 100644 --- a/opendaimon-telegram/pom.xml +++ b/opendaimon-telegram/pom.xml @@ -36,6 +36,10 @@ opendaimon-common ${project.version} + + io.github.ngirchev + fsm + @@ -47,53 +51,201 @@ jackson-module-jaxb-annotations - ${telegram.version} + + + org.telegram + telegrambots-meta + + + + org.apache.httpcomponents + httpclient + + + org.springframework + spring-core + + + org.springframework + spring-beans + + + org.springframework + spring-context + + + org.springframework + spring-tx + + + org.springframework.boot - spring-boot-autoconfigure + spring-boot org.springframework.boot - spring-boot-starter-data-redis + spring-boot-autoconfigure + + + + + org.springframework.data + spring-data-commons + + + org.springframework.data + spring-data-jpa + + + + org.springframework.data + spring-data-redis true + + + + org.springframework.ai + spring-ai-model + + + + + io.projectreactor + reactor-core + + + org.reactivestreams + reactive-streams + + + + + jakarta.persistence + jakarta.persistence-api + + + + + jakarta.validation + jakarta.validation-api + + + + + jakarta.annotation + jakarta.annotation-api + + + org.jetbrains + annotations + + + org.flywaydb flyway-core + + + + org.slf4j + slf4j-api + + + org.projectlombok lombok + provided true + + + com.fasterxml.jackson.core + jackson-databind + + + com.fasterxml.jackson.core + jackson-core + + + + + org.apache.commons + commons-lang3 + + + + + com.github.ben-manes.caffeine + caffeine + + + + + io.micrometer + micrometer-core + test + + + org.springframework + spring-test + test + org.springframework.boot - spring-boot-starter-test + spring-boot-test test - org.flywaydb - flyway-database-postgresql + org.junit.jupiter + junit-jupiter-api test - org.testcontainers - testcontainers + org.mockito + mockito-core test - org.testcontainers - postgresql + org.mockito + mockito-junit-jupiter + test + + + org.assertj + assertj-core test org.testcontainers - junit-jupiter + postgresql test - \ No newline at end of file + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + + true + + org.springframework.boot:spring-boot-starter* + + + + + + + + diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/HistoryTelegramCommandHandler.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/HistoryTelegramCommandHandler.java index 3102fa0b..e6cfd605 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/HistoryTelegramCommandHandler.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/HistoryTelegramCommandHandler.java @@ -7,9 +7,9 @@ import io.github.ngirchev.opendaimon.common.model.OpenDaimonMessage; import io.github.ngirchev.opendaimon.common.model.MessageRole; import io.github.ngirchev.opendaimon.common.model.ThreadScopeKind; -import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; -import io.github.ngirchev.opendaimon.common.repository.OpenDaimonMessageRepository; +import io.github.ngirchev.opendaimon.common.service.ConversationThreadService; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; +import io.github.ngirchev.opendaimon.common.service.OpenDaimonMessageService; import io.github.ngirchev.opendaimon.telegram.TelegramBot; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; @@ -28,20 +28,20 @@ @Slf4j public class HistoryTelegramCommandHandler extends AbstractTelegramCommandHandlerWithResponseSend { - private final ConversationThreadRepository threadRepository; - private final OpenDaimonMessageRepository messageRepository; + private final ConversationThreadService threadService; + private final OpenDaimonMessageService messageService; private final TelegramUserService userService; public HistoryTelegramCommandHandler( ObjectProvider telegramBotProvider, TypingIndicatorService typingIndicatorService, MessageLocalizationService messageLocalizationService, - ConversationThreadRepository threadRepository, - OpenDaimonMessageRepository messageRepository, + ConversationThreadService threadService, + OpenDaimonMessageService messageService, TelegramUserService userService) { super(telegramBotProvider, typingIndicatorService, messageLocalizationService); - this.threadRepository = threadRepository; - this.messageRepository = messageRepository; + this.threadService = threadService; + this.messageService = messageService; this.userService = userService; } @@ -65,13 +65,13 @@ public String handleInner(TelegramCommand command) throws TelegramCommandHandler throw new TelegramCommandHandlerException(command.telegramId(), "Message is required for history command"); } userService.getOrCreateUser(message.getFrom()); - Optional threadOpt = threadRepository.findMostRecentActiveThread( + Optional threadOpt = threadService.findCurrentThread( ThreadScopeKind.TELEGRAM_CHAT, command.telegramId()); if (threadOpt.isEmpty()) { return "❌ You have no active conversation. Start one by sending a message."; } ConversationThread thread = threadOpt.get(); - List messages = messageRepository.findByThreadOrderBySequenceNumberAsc(thread); + List messages = messageService.findByThreadOrderBySequenceNumberAsc(thread); if (messages.isEmpty()) { return "📝 Conversation history is empty.\n\nThread ID: `" + thread.getThreadKey().substring(0, 8) + "...`"; } diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/NewThreadTelegramCommandHandler.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/NewThreadTelegramCommandHandler.java index 560c3538..4bd9c0df 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/NewThreadTelegramCommandHandler.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/NewThreadTelegramCommandHandler.java @@ -6,7 +6,6 @@ import io.github.ngirchev.opendaimon.common.command.ICommand; import io.github.ngirchev.opendaimon.common.model.ConversationThread; import io.github.ngirchev.opendaimon.common.model.ThreadScopeKind; -import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; import io.github.ngirchev.opendaimon.common.service.ConversationThreadService; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; import io.github.ngirchev.opendaimon.telegram.TelegramBot; @@ -19,8 +18,6 @@ import io.github.ngirchev.opendaimon.telegram.service.TelegramUserService; import io.github.ngirchev.opendaimon.telegram.service.TypingIndicatorService; -import java.util.Optional; - /** * Handler for /newthread command to start a new conversation. */ @@ -28,7 +25,6 @@ public class NewThreadTelegramCommandHandler extends AbstractTelegramCommandHandlerWithResponseSend { private final ConversationThreadService threadService; - private final ConversationThreadRepository threadRepository; private final TelegramUserService userService; private final ObjectProvider persistentKeyboardServiceProvider; @@ -37,12 +33,10 @@ public NewThreadTelegramCommandHandler( TypingIndicatorService typingIndicatorService, MessageLocalizationService messageLocalizationService, ConversationThreadService threadService, - ConversationThreadRepository threadRepository, TelegramUserService userService, ObjectProvider persistentKeyboardServiceProvider) { super(telegramBotProvider, typingIndicatorService, messageLocalizationService); this.threadService = threadService; - this.threadRepository = threadRepository; this.userService = userService; this.persistentKeyboardServiceProvider = persistentKeyboardServiceProvider; } @@ -72,10 +66,7 @@ public String handleInner(TelegramCommand command) throws TelegramCommandHandler Long chatId = command.telegramId(); // Close current thread (if any active) - Optional currentThread = threadRepository.findMostRecentActiveThread( - ThreadScopeKind.TELEGRAM_CHAT, chatId); - boolean hadPreviousThread = currentThread.isPresent(); - currentThread.ifPresent(threadService::closeThread); + boolean hadPreviousThread = threadService.closeCurrentThread(ThreadScopeKind.TELEGRAM_CHAT, chatId); // Create new thread — thread.user is the invoker (audit), scope is per-chat. ConversationThread newThread = threadService.createNewThread(user, ThreadScopeKind.TELEGRAM_CHAT, chatId); diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/ThreadsTelegramCommandHandler.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/ThreadsTelegramCommandHandler.java index 72bb2f9e..358be1ae 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/ThreadsTelegramCommandHandler.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/ThreadsTelegramCommandHandler.java @@ -13,7 +13,6 @@ import io.github.ngirchev.opendaimon.common.command.ICommand; import io.github.ngirchev.opendaimon.common.model.ConversationThread; import io.github.ngirchev.opendaimon.common.model.ThreadScopeKind; -import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; import io.github.ngirchev.opendaimon.common.service.ConversationThreadService; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; import io.github.ngirchev.opendaimon.telegram.TelegramBot; @@ -38,7 +37,6 @@ public class ThreadsTelegramCommandHandler extends AbstractTelegramCommandHandle private static final String CALLBACK_PREFIX = "THREADS_"; private static final String CALLBACK_CANCEL = CALLBACK_PREFIX + "CANCEL"; - private final ConversationThreadRepository threadRepository; private final ConversationThreadService threadService; private final TelegramUserService userService; @@ -46,11 +44,9 @@ public ThreadsTelegramCommandHandler( ObjectProvider telegramBotProvider, TypingIndicatorService typingIndicatorService, MessageLocalizationService messageLocalizationService, - ConversationThreadRepository threadRepository, ConversationThreadService threadService, TelegramUserService userService) { super(telegramBotProvider, typingIndicatorService, messageLocalizationService); - this.threadRepository = threadRepository; this.threadService = threadService; this.userService = userService; } @@ -103,8 +99,7 @@ public String handleInner(TelegramCommand command) throws TelegramCommandHandler String lang = command.languageCode(); // Get all threads (active and inactive) - List allThreads = threadRepository.findByScopeKindAndScopeIdOrderByLastActivityAtDesc( - ThreadScopeKind.TELEGRAM_CHAT, chatId); + List allThreads = threadService.findThreads(ThreadScopeKind.TELEGRAM_CHAT, chatId); if (allThreads.isEmpty()) { return messageLocalizationService.getMessage("telegram.threads.empty", lang); @@ -203,8 +198,7 @@ private void handleCallbackQuery(TelegramCommand command) throws TelegramCommand private void sendMessageWithMenu(Long chatId, String text, TelegramCommand command, String lang) throws TelegramCommandHandlerException { try { userService.getOrCreateUser(command.update().getMessage().getFrom()); - List allThreads = threadRepository.findByScopeKindAndScopeIdOrderByLastActivityAtDesc( - ThreadScopeKind.TELEGRAM_CHAT, chatId); + List allThreads = threadService.findThreads(ThreadScopeKind.TELEGRAM_CHAT, chatId); if (allThreads.isEmpty()) { sendMessage(chatId, text); diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/config/TelegramCommandHandlerConfig.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/config/TelegramCommandHandlerConfig.java index 10fb14e6..fea2009f 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/config/TelegramCommandHandlerConfig.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/config/TelegramCommandHandlerConfig.java @@ -14,7 +14,6 @@ import io.github.ngirchev.opendaimon.common.agent.AgentExecutor; import io.github.ngirchev.opendaimon.common.ai.pipeline.AIRequestPipeline; import io.github.ngirchev.opendaimon.common.config.CoreCommonProperties; -import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; import io.github.ngirchev.opendaimon.common.repository.OpenDaimonMessageRepository; import io.github.ngirchev.opendaimon.common.service.*; import io.github.ngirchev.opendaimon.telegram.TelegramBot; @@ -151,7 +150,6 @@ public NewThreadTelegramCommandHandler newThreadTelegramCommandHandler( TypingIndicatorService typingIndicatorService, MessageLocalizationService messageLocalizationService, ConversationThreadService threadService, - ConversationThreadRepository threadRepository, TelegramUserService telegramUserService, ObjectProvider persistentKeyboardServiceProvider) { return new NewThreadTelegramCommandHandler( @@ -159,7 +157,6 @@ public NewThreadTelegramCommandHandler newThreadTelegramCommandHandler( typingIndicatorService, messageLocalizationService, threadService, - threadRepository, telegramUserService, persistentKeyboardServiceProvider); } @@ -171,15 +168,15 @@ public HistoryTelegramCommandHandler historyTelegramCommandHandler( ObjectProvider telegramBotProvider, TypingIndicatorService typingIndicatorService, MessageLocalizationService messageLocalizationService, - ConversationThreadRepository threadRepository, - OpenDaimonMessageRepository messageRepository, + ConversationThreadService threadService, + OpenDaimonMessageService messageService, TelegramUserService telegramUserService) { return new HistoryTelegramCommandHandler( telegramBotProvider, typingIndicatorService, messageLocalizationService, - threadRepository, - messageRepository, + threadService, + messageService, telegramUserService); } @@ -190,14 +187,12 @@ public ThreadsTelegramCommandHandler threadsTelegramCommandHandler( ObjectProvider telegramBotProvider, TypingIndicatorService typingIndicatorService, MessageLocalizationService messageLocalizationService, - ConversationThreadRepository threadRepository, ConversationThreadService threadService, TelegramUserService telegramUserService) { return new ThreadsTelegramCommandHandler( telegramBotProvider, typingIndicatorService, messageLocalizationService, - threadRepository, threadService, telegramUserService); } diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramGroupRepository.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramGroupRepository.java index 857e9575..855051ac 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramGroupRepository.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramGroupRepository.java @@ -1,12 +1,10 @@ package io.github.ngirchev.opendaimon.telegram.repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; import io.github.ngirchev.opendaimon.telegram.model.TelegramGroup; import java.util.Optional; -@Repository public interface TelegramGroupRepository extends JpaRepository { Optional findByTelegramId(Long telegramId); diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramUserRepository.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramUserRepository.java index b5dde696..8c0a6f61 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramUserRepository.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramUserRepository.java @@ -1,12 +1,10 @@ package io.github.ngirchev.opendaimon.telegram.repository; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; import io.github.ngirchev.opendaimon.telegram.model.TelegramUser; import java.util.Optional; -@Repository public interface TelegramUserRepository extends JpaRepository { Optional findByTelegramId(Long telegramId); diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramUserSessionRepository.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramUserSessionRepository.java index da0128c6..3ce1aff2 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramUserSessionRepository.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramUserSessionRepository.java @@ -5,7 +5,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; import io.github.ngirchev.opendaimon.telegram.model.TelegramUser; import io.github.ngirchev.opendaimon.telegram.model.TelegramUserSession; @@ -13,7 +12,6 @@ import java.util.List; import java.util.Optional; -@Repository public interface TelegramUserSessionRepository extends JpaRepository { Optional findByTelegramUserAndSessionId(TelegramUser telegramUser, String sessionId); diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramWhitelistRepository.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramWhitelistRepository.java index 3bcd877a..b2554f52 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramWhitelistRepository.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/repository/TelegramWhitelistRepository.java @@ -3,13 +3,11 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.springframework.stereotype.Repository; import io.github.ngirchev.opendaimon.telegram.model.TelegramUser; import io.github.ngirchev.opendaimon.telegram.model.TelegramWhitelist; import java.util.List; -@Repository public interface TelegramWhitelistRepository extends JpaRepository { @Query("SELECT COUNT(w) > 0 FROM TelegramWhitelist w WHERE w.user.id = :userId") boolean existsByUserId(@Param("userId") Long userId); diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/StartTelegramTextCommandHandlerProviderTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/StartTelegramTextCommandHandlerProviderTest.java index 1cd17e60..486021f8 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/StartTelegramTextCommandHandlerProviderTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/StartTelegramTextCommandHandlerProviderTest.java @@ -8,7 +8,6 @@ import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; -import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.TestPropertySource; import io.github.ngirchev.opendaimon.bulkhead.service.IUserPriorityService; import io.github.ngirchev.opendaimon.bulkhead.service.PriorityRequestExecutor; @@ -55,7 +54,6 @@ @SpringBootTest(classes = { TelegramCommandHandlerConfig.class }) -@ActiveProfiles("test") @Import(StartTelegramTextCommandHandlerProviderTest.TestConfig.class) @TestPropertySource(properties = { "open-daimon.telegram.enabled=true", @@ -321,4 +319,3 @@ public UserRepository userRepository() { } } } - diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/HistoryTelegramCommandHandlerTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/HistoryTelegramCommandHandlerTest.java index fbbc745f..0d181044 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/HistoryTelegramCommandHandlerTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/HistoryTelegramCommandHandlerTest.java @@ -4,9 +4,9 @@ import io.github.ngirchev.opendaimon.common.model.ConversationThread; import io.github.ngirchev.opendaimon.common.model.MessageRole; import io.github.ngirchev.opendaimon.common.model.ThreadScopeKind; -import io.github.ngirchev.opendaimon.common.repository.OpenDaimonMessageRepository; -import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; +import io.github.ngirchev.opendaimon.common.service.ConversationThreadService; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; +import io.github.ngirchev.opendaimon.common.service.OpenDaimonMessageService; import io.github.ngirchev.opendaimon.telegram.command.handler.TelegramCommandHandlerException; import io.github.ngirchev.opendaimon.telegram.TelegramBot; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; @@ -51,9 +51,9 @@ class HistoryTelegramCommandHandlerTest { @Mock private TypingIndicatorService typingIndicatorService; @Mock - private ConversationThreadRepository threadRepository; + private ConversationThreadService threadService; @Mock - private OpenDaimonMessageRepository messageRepository; + private OpenDaimonMessageService messageService; @Mock private TelegramUserService userService; @@ -73,7 +73,7 @@ void setUp() { handler = new HistoryTelegramCommandHandler( botProvider, typingIndicatorService, messageLocalizationService, - threadRepository, messageRepository, userService); + threadService, messageService, userService); } @Test @@ -127,7 +127,7 @@ void handleInner_whenNoActiveThread_returnsNoConversationMessage() { TelegramUser telegramUser = new TelegramUser(); when(userService.getOrCreateUser(any())).thenReturn(telegramUser); - when(threadRepository.findMostRecentActiveThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(Optional.empty()); + when(threadService.findCurrentThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(Optional.empty()); TelegramCommand command = new TelegramCommand(100L, CHAT_ID, new TelegramCommandType(TelegramCommand.HISTORY), update); @@ -149,8 +149,8 @@ void handleInner_whenEmptyMessages_returnsEmptyHistoryMessage() { ConversationThread thread = new ConversationThread(); thread.setThreadKey("thread-key-12"); when(userService.getOrCreateUser(any())).thenReturn(telegramUser); - when(threadRepository.findMostRecentActiveThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(Optional.of(thread)); - when(messageRepository.findByThreadOrderBySequenceNumberAsc(thread)).thenReturn(List.of()); + when(threadService.findCurrentThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(Optional.of(thread)); + when(messageService.findByThreadOrderBySequenceNumberAsc(thread)).thenReturn(List.of()); TelegramCommand command = new TelegramCommand(100L, CHAT_ID, new TelegramCommandType(TelegramCommand.HISTORY), update); @@ -173,7 +173,7 @@ void handleInner_whenHasMessages_returnsFormattedHistory() { ConversationThread thread = new ConversationThread(); thread.setThreadKey("thread-key-ab"); when(userService.getOrCreateUser(any())).thenReturn(telegramUser); - when(threadRepository.findMostRecentActiveThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(Optional.of(thread)); + when(threadService.findCurrentThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(Optional.of(thread)); OpenDaimonMessage userMsg = new OpenDaimonMessage(); userMsg.setRole(MessageRole.USER); @@ -181,7 +181,7 @@ void handleInner_whenHasMessages_returnsFormattedHistory() { OpenDaimonMessage assistantMsg = new OpenDaimonMessage(); assistantMsg.setRole(MessageRole.ASSISTANT); assistantMsg.setContent("Hi there"); - when(messageRepository.findByThreadOrderBySequenceNumberAsc(thread)) + when(messageService.findByThreadOrderBySequenceNumberAsc(thread)) .thenReturn(List.of(userMsg, assistantMsg)); TelegramCommand command = new TelegramCommand(100L, CHAT_ID, @@ -194,7 +194,7 @@ void handleInner_whenHasMessages_returnsFormattedHistory() { assertTrue(result.contains("Hello")); assertTrue(result.contains("Hi there")); assertTrue(result.contains("Total messages: 2")); - verify(messageRepository).findByThreadOrderBySequenceNumberAsc(thread); + verify(messageService).findByThreadOrderBySequenceNumberAsc(thread); } @Test diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/NewThreadTelegramCommandHandlerTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/NewThreadTelegramCommandHandlerTest.java index 0c7c6b0d..63f8c735 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/NewThreadTelegramCommandHandlerTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/NewThreadTelegramCommandHandlerTest.java @@ -1,8 +1,7 @@ package io.github.ngirchev.opendaimon.telegram.command.handler.impl; -import io.github.ngirchev.opendaimon.common.model.ConversationThread; import io.github.ngirchev.opendaimon.common.model.ThreadScopeKind; -import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; +import io.github.ngirchev.opendaimon.common.model.ConversationThread; import io.github.ngirchev.opendaimon.common.service.ConversationThreadService; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; import io.github.ngirchev.opendaimon.telegram.command.handler.TelegramCommandHandlerException; @@ -26,8 +25,6 @@ import org.telegram.telegrambots.meta.api.objects.Update; import org.telegram.telegrambots.meta.api.objects.User; -import java.util.Optional; - import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -51,8 +48,6 @@ class NewThreadTelegramCommandHandlerTest { @Mock private ConversationThreadService threadService; @Mock - private ConversationThreadRepository threadRepository; - @Mock private TelegramUserService userService; @Mock private ObjectProvider persistentKeyboardServiceProvider; @@ -72,7 +67,7 @@ void setUp() { handler = new NewThreadTelegramCommandHandler( botProvider, typingIndicatorService, messageLocalizationService, - threadService, threadRepository, userService, persistentKeyboardServiceProvider); + threadService, userService, persistentKeyboardServiceProvider); } @Test @@ -134,7 +129,7 @@ void handleInner_whenNoPreviousThread_createsNewAndReturnsMessage() { telegramUser.setTelegramId(100L); telegramUser.setLanguageCode("en"); when(userService.getOrCreateUser(from)).thenReturn(telegramUser); - when(threadRepository.findMostRecentActiveThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(Optional.empty()); + when(threadService.closeCurrentThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(false); ConversationThread newThread = new ConversationThread(); newThread.setThreadKey("thread-key-abcdef12"); @@ -148,8 +143,8 @@ void handleInner_whenNoPreviousThread_createsNewAndReturnsMessage() { assertNotNull(result); assertTrue(result.contains("New conversation started")); assertTrue(result.contains("Thread ID:")); + verify(threadService).closeCurrentThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID); verify(threadService).createNewThread(telegramUser, ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID); - verify(threadRepository).findMostRecentActiveThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID); } @Test @@ -165,10 +160,7 @@ void handleInner_whenHasPreviousThread_closesAndCreatesNew() { telegramUser.setLanguageCode("en"); when(userService.getOrCreateUser(from)).thenReturn(telegramUser); - ConversationThread oldThread = new ConversationThread(); - oldThread.setId(1L); - oldThread.setThreadKey("old-key"); - when(threadRepository.findMostRecentActiveThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(Optional.of(oldThread)); + when(threadService.closeCurrentThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(true); ConversationThread newThread = new ConversationThread(); newThread.setThreadKey("new-thread-key-12"); @@ -181,7 +173,7 @@ void handleInner_whenHasPreviousThread_closesAndCreatesNew() { assertNotNull(result); assertTrue(result.contains("Previous conversation history was saved")); - verify(threadService).closeThread(oldThread); + verify(threadService).closeCurrentThread(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID); verify(threadService).createNewThread(telegramUser, ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID); } diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/ThreadsTelegramCommandHandlerTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/ThreadsTelegramCommandHandlerTest.java index 99497b11..6a56445e 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/ThreadsTelegramCommandHandlerTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/ThreadsTelegramCommandHandlerTest.java @@ -18,7 +18,6 @@ import org.telegram.telegrambots.meta.api.objects.User; import io.github.ngirchev.opendaimon.common.model.ConversationThread; import io.github.ngirchev.opendaimon.common.model.ThreadScopeKind; -import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; import io.github.ngirchev.opendaimon.common.service.ConversationThreadService; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; import io.github.ngirchev.opendaimon.telegram.TelegramBot; @@ -55,8 +54,6 @@ class ThreadsTelegramCommandHandlerTest { @Mock private TypingIndicatorService typingIndicatorService; @Mock - private ConversationThreadRepository threadRepository; - @Mock private ConversationThreadService threadService; @Mock private TelegramUserService userService; @@ -76,7 +73,7 @@ void setUp() { when(botProvider.getObject()).thenReturn(telegramBot); handler = new ThreadsTelegramCommandHandler(botProvider, typingIndicatorService, messageLocalizationService, - threadRepository, threadService, userService); + threadService, userService); } @Test @@ -150,8 +147,7 @@ void handleInner_whenNoThreads_thenReturnsNoConversationsMessage() { TelegramUser user = new TelegramUser(); user.setTelegramId(200L); when(userService.getOrCreateUser(any(User.class))).thenReturn(user); - when(threadRepository.findByScopeKindAndScopeIdOrderByLastActivityAtDesc( - ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(List.of()); + when(threadService.findThreads(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(List.of()); TelegramCommand command = new TelegramCommand(200L, CHAT_ID, new TelegramCommandType(TelegramCommand.THREADS), update); command.languageCode("en"); @@ -180,8 +176,7 @@ void handleInner_whenHasThreads_thenSendsListWithMenuAndCancelRow() throws Teleg thread.setScopeId(CHAT_ID); when(userService.getOrCreateUser(from)).thenReturn(user); - when(threadRepository.findByScopeKindAndScopeIdOrderByLastActivityAtDesc( - ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(List.of(thread)); + when(threadService.findThreads(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(List.of(thread)); TelegramCommand command = new TelegramCommand(200L, CHAT_ID, new TelegramCommandType(TelegramCommand.THREADS), update); command.languageCode("en"); @@ -335,8 +330,7 @@ void handle_whenPlainCommand_doesNotStartTyping() { TelegramUser user = new TelegramUser(); user.setTelegramId(200L); when(userService.getOrCreateUser(any(User.class))).thenReturn(user); - when(threadRepository.findByScopeKindAndScopeIdOrderByLastActivityAtDesc( - ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(List.of()); + when(threadService.findThreads(ThreadScopeKind.TELEGRAM_CHAT, CHAT_ID)).thenReturn(List.of()); TelegramCommand command = new TelegramCommand(200L, CHAT_ID, new TelegramCommandType(TelegramCommand.THREADS), update); command.languageCode("en"); diff --git a/opendaimon-ui/pom.xml b/opendaimon-ui/pom.xml index db3d0440..426650cd 100644 --- a/opendaimon-ui/pom.xml +++ b/opendaimon-ui/pom.xml @@ -44,42 +44,75 @@ opendaimon-rest ${project.version} - + + - org.springframework.boot - spring-boot-starter-web - - - org.springframework.boot - spring-boot-starter-logging - - + org.springframework + spring-context + + org.springframework + spring-web + + + org.springframework.boot - spring-boot-starter-validation + spring-boot org.springframework.boot - spring-boot-starter-thymeleaf + spring-boot-autoconfigure + - org.projectlombok - lombok - true + org.apache.tomcat.embed + tomcat-embed-core + + + org.apache.tomcat + tomcat-annotations-api + + - + - org.springframework.boot - spring-boot-starter-test - test + org.slf4j + slf4j-api + + - org.mockito - mockito-junit-jupiter - test + org.projectlombok + lombok + provided + true - \ No newline at end of file + + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + enforce-dependency-graph + + + + true + + org.springframework.boot:spring-boot-starter* + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 584cb521..0be764d6 100644 --- a/pom.xml +++ b/pom.xml @@ -77,32 +77,39 @@ 3.11.0 - 3.4.4 - 3.4.4 - 6.2.6 - 3.4.4 + 3.5.13 + 3.5.13 2.8.6 1.3.2 - 42.7.3 - 11.4.1 - 4.0.1 + 42.7.10 + 11.7.2 + 4.0.4 + 4.0.5 - 1.18.30 + 1.18.44 1.14.12 - 1.13.5 0.10.4 - 3.14.0 + 3.18.0 + 4.13.1 + 2.2.0 + 1.19.0 + 4.5.0 + 1.28.0 + 2.5 + 3.52.0 + 1.81 6.9.7.0 2.1.0 3.1.8 8.5.7 + 1.4.2 4.12.0 5.10.0 - 1.20.0 - 2.2.224 + 1.21.4 + 2.3.232 1.1.2 @@ -118,18 +125,21 @@ 5.5.0.6356 2.20.0 1.1.0 + 3.8.1 + 3.6.2 + 24.1.0 + 3.2.3 + 2.2.38 + 4.5.14 + 11.7.2 + 3.0.5 + 1.21.2 + 7.4 - - org.springframework - spring-framework-bom - ${org.springframework.version} - pom - import - org.springframework.boot spring-boot-dependencies @@ -158,12 +168,6 @@ 1.0.5 - - org.springframework.boot - spring-boot-starter-thymeleaf - ${spring-thymeleaf.version} - - org.springdoc @@ -197,13 +201,7 @@ org.glassfish.jaxb jaxb-runtime - 2.3.3 - - - - io.micrometer - micrometer-registry-prometheus - ${micrometer-prometheus.version} + ${jaxb-runtime.version} @@ -221,6 +219,51 @@ vavr ${vavr.version} + + org.antlr + antlr4-runtime + ${antlr4-runtime.version} + + + org.jetbrains.kotlin + kotlin-stdlib + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-reflect + ${kotlin.version} + + + commons-codec + commons-codec + ${commons-codec.version} + + + org.apache.commons + commons-collections4 + ${commons-collections4.version} + + + org.apache.commons + commons-compress + ${commons-compress.version} + + + org.yaml + snakeyaml + ${snakeyaml.version} + + + org.checkerframework + checker-qual + ${checker-qual.version} + + + org.bouncycastle + bcprov-jdk18on + ${bouncycastle.version} + @@ -261,6 +304,124 @@ commons-io ${commons-io.version} + + + + com.github.ben-manes.caffeine + caffeine + ${caffeine.version} + + + + + org.jetbrains + annotations + ${jetbrains-annotations.version} + + + + + io.minio + minio + ${minio.version} + + + + + io.github.resilience4j + resilience4j-spring-boot2 + ${resilience4j.version} + + + io.github.resilience4j + resilience4j-bulkhead + ${resilience4j.version} + + + + + org.telegram + telegrambots + ${telegram.version} + + + org.telegram + telegrambots-meta + ${telegram.version} + + + + + org.apache.tika + tika-core + ${tika-core.version} + + + + + com.squareup.okhttp3 + okhttp + ${okhttp.version} + + + + + io.swagger.core.v3 + swagger-annotations-jakarta + ${swagger-annotations-jakarta.version} + + + + + org.apache.httpcomponents + httpclient + ${httpclient.version} + + + commons-logging + commons-logging + + + + + + + org.flywaydb + flyway-database-postgresql + ${flyway-database-postgresql.version} + + + + + org.apache.pdfbox + pdfbox + ${pdfbox.version} + + + commons-logging + commons-logging + + + + + org.apache.pdfbox + pdfbox-io + ${pdfbox.version} + + + + + org.jsoup + jsoup + ${jsoup.version} + + + + + net.logstash.logback + logstash-logback-encoder + ${logstash-logback-encoder.version} + @@ -395,6 +556,56 @@ + + + + org.apache.maven.plugins + maven-dependency-plugin + ${maven-dependency-plugin.version} + + + analyze + verify + + analyze-only + + + true + true + true + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + ${maven-enforcer-plugin.version} + + + enforce-dependency-graph + verify + + enforce + + + + + + + true + + commons-logging:commons-logging + + + + true + + + + @@ -406,6 +617,14 @@ org.jacoco jacoco-maven-plugin + + org.apache.maven.plugins + maven-dependency-plugin + + + org.apache.maven.plugins + maven-enforcer-plugin + @@ -456,4 +675,4 @@ - \ No newline at end of file + From 9e692792f5cee9634477d8bd87ffd4b7c6d40a74 Mon Sep 17 00:00:00 2001 From: ngirchev Date: Fri, 1 May 2026 17:21:37 +0300 Subject: [PATCH 2/7] Changed license --- AGENTS.md | 17 +- CONTRIBUTING.md | 10 + LICENSE | 203 ++++++- NOTICE | 6 + README.md | 10 +- TODO.md | 25 +- TRADEMARKS.md | 18 + cli/package-lock.json | 2 +- cli/package.json | 4 +- docs/team/archunit-rules.md | 507 ++++-------------- ...legramMessageHandlerActionsTestWiring.java | 12 +- .../it/config/AgentAutoConfigSmokeIT.java | 2 +- .../it/config/CoreAutoConfigSmokeIT.java | 2 +- .../fixture/config/TelegramFixtureConfig.java | 18 +- .../it/telegram/TelegramMockGatewayIT.java | 12 +- .../MessageTelegramCommandHandlerIT.java | 17 +- .../{handler => command}/RestChatCommand.java | 12 +- .../RestChatCommandType.java | 2 +- .../AdminConversationController.java | 95 +++- .../rest/controller/AdminUserController.java | 25 +- .../rest/controller/SessionController.java | 42 +- .../rest/handler/RestChatHandlerSupport.java | 1 + .../RestChatMessageCommandHandler.java | 11 +- .../RestChatStreamMessageCommandHandler.java | 11 +- .../rest/service/AdminQueryService.java | 50 +- .../opendaimon/rest/service/ChatService.java | 34 +- .../service/model/AdminAttachmentRef.java | 11 + .../model/AdminConversationSummary.java | 18 + .../service/model/AdminMessageDetail.java | 26 + .../service/model/AdminMessageSummary.java | 15 + .../rest/service/model/AdminPageResponse.java | 23 + .../rest/service/model/AdminUserSummary.java | 13 + .../rest/service/model/ChatMessage.java | 4 + .../rest/service/model/ChatResponse.java | 4 + .../rest/service/model/ChatSession.java | 6 + .../rest/arch/RestArchitectureTest.java | 158 ++---- .../SessionControllerContractTest.java | 26 +- .../handler/RestChatHandlerSupportTest.java | 15 +- .../RestChatMessageCommandHandlerTest.java | 30 +- ...stChatStreamMessageCommandHandlerTest.java | 30 +- .../rest/service/AdminQueryServiceTest.java | 18 +- .../rest/service/ChatServiceTest.java | 18 +- opendaimon-spring-ai/pom.xml | 21 + .../{agent => config}/AgentAutoConfig.java | 11 +- .../{agent => config}/AgentProperties.java | 3 +- .../OpenRouterModelsProperties.java | 2 +- .../springai/config/SpringAIAutoConfig.java | 1 - .../retry/OpenRouterFreeModelResolver.java | 1 + .../springai/retry/SpringAIModelRegistry.java | 1 + ...ot.autoconfigure.AutoConfiguration.imports | 2 +- .../arch/SpringAIArchitectureTest.java | 116 ++++ .../retry/ModelSelectionPriorityTest.java | 1 + .../OpenRouterEmbeddingModelsFetchTest.java | 1 + .../OpenRouterFreeModelResolverTest.java | 1 + .../retry/SpringAIModelRegistryTest.java | 1 + opendaimon-telegram/pom.xml | 29 + .../TelegramSupportedCommandProvider.java | 4 +- .../AbstractTelegramCommandHandler.java | 1 + ...elegramCommandHandlerWithResponseSend.java | 1 + .../handler/impl/BackoffCommandHandler.java | 2 +- .../impl/MessageTelegramCommandHandler.java | 8 +- .../impl/StartTelegramCommandHandler.java | 2 +- .../config/TelegramCommandHandlerConfig.java | 16 +- .../config/TelegramServiceConfig.java | 2 +- .../service/TelegramAgentStreamRenderer.java | 2 +- .../service/TelegramAgentStreamView.java | 4 +- .../service/TelegramBotMenuService.java | 2 +- .../TelegramDeliveryFailedException.java | 2 +- .../TelegramMessageSender.java | 2 +- .../fsm/MessageHandlerActions.java | 2 +- .../fsm/MessageHandlerContext.java | 2 +- .../fsm/MessageHandlerErrorType.java | 2 +- .../fsm/MessageHandlerEvent.java | 2 +- .../fsm/MessageHandlerFsmFactory.java | 6 +- .../fsm/MessageHandlerState.java | 2 +- .../fsm/TelegramMessageHandlerActions.java | 4 +- .../arch/TelegramArchitectureTest.java | 83 +++ ...elegramTextCommandHandlerProviderTest.java | 2 +- .../impl/BackoffCommandHandlerTest.java | 2 +- .../MessageTelegramCommandHandlerTest.java | 12 +- .../impl/StartTelegramCommandHandlerTest.java | 2 +- .../TelegramAgentStreamRendererTest.java | 2 +- ...elegramAgentStreamViewConcurrencyTest.java | 4 +- .../service/TelegramAgentStreamViewTest.java | 4 +- .../service/TelegramBotMenuServiceTest.java | 2 +- .../fsm/MessageHandlerContextTest.java | 2 +- ...elegramMessageHandlerActionsAgentTest.java | 3 +- ...ramMessageHandlerActionsStreamingTest.java | 3 +- pom.xml | 4 +- 89 files changed, 1137 insertions(+), 810 deletions(-) create mode 100644 NOTICE create mode 100644 TRADEMARKS.md rename opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/{handler => command}/RestChatCommand.java (70%) rename opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/{handler => command}/RestChatCommandType.java (74%) create mode 100644 opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminAttachmentRef.java create mode 100644 opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminConversationSummary.java create mode 100644 opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminMessageDetail.java create mode 100644 opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminMessageSummary.java create mode 100644 opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminPageResponse.java create mode 100644 opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminUserSummary.java create mode 100644 opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/ChatMessage.java create mode 100644 opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/ChatResponse.java create mode 100644 opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/ChatSession.java rename opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/{agent => config}/AgentAutoConfig.java (91%) rename opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/{agent => config}/AgentProperties.java (91%) rename opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/{retry => config}/OpenRouterModelsProperties.java (99%) create mode 100644 opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/arch/SpringAIArchitectureTest.java rename opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/{handler => }/TelegramSupportedCommandProvider.java (87%) rename opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/{command/handler/impl/fsm => service}/TelegramDeliveryFailedException.java (79%) rename opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/{command/handler/impl/fsm => service}/TelegramMessageSender.java (99%) rename opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/{command/handler/impl => service}/fsm/MessageHandlerActions.java (97%) rename opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/{command/handler/impl => service}/fsm/MessageHandlerContext.java (99%) rename opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/{command/handler/impl => service}/fsm/MessageHandlerErrorType.java (92%) rename opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/{command/handler/impl => service}/fsm/MessageHandlerEvent.java (80%) rename opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/{command/handler/impl => service}/fsm/MessageHandlerFsmFactory.java (94%) rename opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/{command/handler/impl => service}/fsm/MessageHandlerState.java (96%) rename opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/{command/handler/impl => service}/fsm/TelegramMessageHandlerActions.java (99%) create mode 100644 opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/arch/TelegramArchitectureTest.java rename opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/{command/handler/impl => service}/fsm/MessageHandlerContextTest.java (96%) rename opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/{command/handler/impl => service}/fsm/TelegramMessageHandlerActionsAgentTest.java (99%) rename opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/{command/handler/impl => service}/fsm/TelegramMessageHandlerActionsStreamingTest.java (99%) diff --git a/AGENTS.md b/AGENTS.md index 0a6af7f3..4ad64ea3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,11 +21,11 @@ Consequences for any change touching `pom.xml`, public types, or shared APIs: ## Rules for AI Agents -### Serena activation on session start +### Serena project context -- At the beginning of each new session in this repository, verify Serena state first. -- If Serena reports `Active Project: None`, immediately call `activate_project("open-daimon")`. -- Do this before any code exploration or edits to ensure project-aware symbol tooling works correctly. +- Before using Serena tools for project-aware navigation, silently verify that the active project is `open-daimon`. +- If Serena is inactive or points to another project, activate `open-daimon`. +- Do not mention this check in user-facing updates unless activation fails or the Serena state is directly relevant to the task. ### MCP tools for information lookup @@ -37,6 +37,15 @@ Consequences for any change touching `pom.xml`, public types, or shared APIs: - Prefer JetBrains MCP for Java refactoring and IDE-backed checks: use it before text-only replacement for renames, before broad shell search when IDE indexing is likely more precise, and for targeted file diagnostics after edits. - Prefer Context7 for Spring AI, OpenAI API, MCP SDK/transport, Maven plugin, and dependency API questions before answering or implementing from memory. +### Code exploration with ast-outline + +- Use `ast-outline` as a pre-read layer for supported source and documentation files when a structural view is enough. +- For unfamiliar directories, start with `ast-outline digest ` to get a compact type and public-method map. +- For file-level shape, use `ast-outline ` to inspect declarations with line ranges and without method bodies. +- For one method, type, markdown heading, or YAML key, use `ast-outline show ` and then read the full file only if the extracted context is not enough. +- For implementation lookups, use `ast-outline implements ` when an AST-based search is more precise than text search. +- Batch paths in one call where useful. `ast-outline` complements `rg`, Serena, and JetBrains; it does not replace IDE-backed symbol navigation or full reads when exact code context is needed. + ### Documentation maintenance - Every module that has a behavior reference doc (e.g. `SPRING_AI_MODULE.md`, `TELEGRAM_MODULE.md`) must be updated when the behavior it describes changes. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 309deec7..78dce6a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -75,6 +75,16 @@ Before submitting a Pull Request, ensure: 4. JavaDoc is added or updated for public APIs where relevant. 5. No secrets or API keys are committed (use environment variables or `.env`). +## Contribution licensing + +By submitting a contribution, you certify that you have the right to submit it +and agree to license it under the Apache License, Version 2.0. + +You also grant Nikolai Girchev a perpetual, worldwide, non-exclusive, +royalty-free right to use, reproduce, modify, distribute, sublicense, and +relicense your contribution as part of OpenDaimon and related commercial or +closed-source products. + ## Security - **API keys and secrets**: Only in environment variables or `.env` (and `.env` must not be committed). diff --git a/LICENSE b/LICENSE index c686a91d..66af111c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,182 @@ -MIT License - -Copyright (c) 2026 Nikolai Girchev - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, +made available under the License, as indicated by a copyright notice that is +included in or attached to the work (an example is provided in the Appendix +below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work by +the copyright owner or by an individual or Legal Entity authorized to submit on +behalf of the copyright owner. For the purposes of this definition, "submitted" +means any form of electronic, verbal, or written communication sent to the +Licensor or its representatives, including but not limited to communication on +electronic mailing lists, source code control systems, and issue tracking systems +that are managed by, or on behalf of, the Licensor for the purpose of discussing +and improving the Work, but excluding communication that is conspicuously marked +or otherwise designated in writing by the copyright owner as "Not a +Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this +License, each Contributor hereby grants to You a perpetual, worldwide, +non-exclusive, no-charge, royalty-free, irrevocable copyright license to +reproduce, prepare Derivative Works of, publicly display, publicly perform, +sublicense, and distribute the Work and such Derivative Works in Source or +Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, +each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, +no-charge, royalty-free, irrevocable (except as stated in this section) patent +license to make, have made, use, offer to sell, sell, import, and otherwise +transfer the Work, where such license applies only to those patent claims +licensable by such Contributor that are necessarily infringed by their +Contribution(s) alone or by combination of their Contribution(s) with the Work to +which such Contribution(s) was submitted. If You institute patent litigation +against any entity (including a cross-claim or counterclaim in a lawsuit) +alleging that the Work or a Contribution incorporated within the Work constitutes +direct or contributory patent infringement, then any patent licenses granted to +You under this License for that Work shall terminate as of the date such +litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or +Derivative Works thereof in any medium, with or without modifications, and in +Source or Object form, provided that You meet the following conditions: + +(a) You must give any other recipients of the Work or Derivative Works a copy of +this License; and + +(b) You must cause any modified files to carry prominent notices stating that You +changed the files; and + +(c) You must retain, in the Source form of any Derivative Works that You +distribute, all copyright, patent, trademark, and attribution notices from the +Source form of the Work, excluding those notices that do not pertain to any part +of the Derivative Works; and + +(d) If the Work includes a "NOTICE" text file as part of its distribution, then +any Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the Derivative +Works; within the Source form or documentation, if provided along with the +Derivative Works; or, within a display generated by the Derivative Works, if and +wherever such third-party notices normally appear. The contents of the NOTICE +file are for informational purposes only and do not modify the License. You may +add Your own attribution notices within Derivative Works that You distribute, +alongside or as an addendum to the NOTICE text from the Work, provided that such +additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any +Contribution intentionally submitted for inclusion in the Work by You to the +Licensor shall be under the terms and conditions of this License, without any +additional terms or conditions. Notwithstanding the above, nothing herein shall +supersede or modify the terms of any separate license agreement you may have +executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, +trademarks, service marks, or product names of the Licensor, except as required +for reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in +writing, Licensor provides the Work (and each Contributor provides its +Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, +either express or implied, including, without limitation, any warranties or +conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A +PARTICULAR PURPOSE. You are solely responsible for determining the +appropriateness of using or redistributing the Work and assume any risks +associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in +tort (including negligence), contract, or otherwise, unless required by +applicable law (such as deliberate and grossly negligent acts) or agreed to in +writing, shall any Contributor be liable to You for damages, including any +direct, indirect, special, incidental, or consequential damages of any character +arising as a result of this License or out of the use or inability to use the +Work (including but not limited to damages for loss of goodwill, work stoppage, +computer failure or malfunction, or any and all other commercial damages or +losses), even if such Contributor has been advised of the possibility of such +damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or +Derivative Works thereof, You may choose to offer, and charge a fee for, +acceptance of support, warranty, indemnity, or other liability obligations and/or +rights consistent with this License. However, in accepting such obligations, You +may act only on Your own behalf and on Your sole responsibility, not on behalf of +any other Contributor, and only if You agree to indemnify, defend, and hold each +Contributor harmless for any liability incurred by, or claims asserted against, +such Contributor by reason of your accepting any such warranty or additional +liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "[]" replaced with your own +identifying information. (Do not include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on the +same "printed page" as the copyright notice for easier identification within +third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 00000000..131397f6 --- /dev/null +++ b/NOTICE @@ -0,0 +1,6 @@ +OpenDaimon +Copyright 2026 Nikolai Girchev + +This product includes software developed by Nikolai Girchev. + +OpenDaimon is distributed under the Apache License, Version 2.0. diff --git a/README.md b/README.md index 1bb61864..0fddaeef 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ [![Java 21](https://img.shields.io/badge/Java-21-ED8B00?logo=openjdk)](https://openjdk.org/) [![Spring Boot 3.3.3](https://img.shields.io/badge/Spring%20Boot-3.3.3-6DB33F?logo=springboot)](https://spring.io/projects/spring-boot) -[![License](https://img.shields.io/github/license/NGirchev/open-daimon)](https://github.com/NGirchev/open-daimon/blob/master/LICENSE) +[![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/NGirchev/open-daimon/blob/master/LICENSE) ## Quick Setup @@ -762,4 +762,10 @@ docker-compose -H tcp://localhost:23750 up -d ## License -See [LICENSE](LICENSE) file for details. +OpenDaimon is licensed under the Apache License, Version 2.0. See +[LICENSE](LICENSE) and [NOTICE](NOTICE) for details. + +The Apache License does not grant trademark rights. If you distribute a fork, +modified version, hosted service, or commercial product based on OpenDaimon, use +a distinct product name and preserve the required attribution notices. See +[TRADEMARKS.md](TRADEMARKS.md). diff --git a/TODO.md b/TODO.md index e527ac3b..24506d37 100644 --- a/TODO.md +++ b/TODO.md @@ -84,29 +84,28 @@ - `org.hibernate.validator:hibernate-validator` is declared as a test-scoped validation provider for `BulkHeadPropertiesTest`; it is not exported as compile API. - ArchUnit test dependencies are declared as direct test dependencies (`archunit`, `archunit-junit5-api`) plus the JUnit Platform runtime engine (`archunit-junit5-engine`) with a targeted analyzer ignore. - Verified with `./mvnw -pl opendaimon-common test dependency:analyze -DskipITs -DskipIT`: 283 tests, 0 failures/errors, 2 skipped; dependency analyzer reports `No dependency problems found`. - - [ ] `opendaimon-spring-ai` module cleanup - - Analyzer warnings observed: - - unused declared `org.springframework.ai:spring-ai-autoconfigure-model-chat-memory:runtime` - - unused declared `org.springframework.ai:spring-ai-autoconfigure-model-chat-memory-repository-jdbc:runtime` - - unused declared `com.h2database:h2:test` - - Decide whether runtime autoconfig glue should be precisely ignored with comments or removed. - - Review `jakarta.persistence-api`: it is currently test-scoped, while compile showed missing enum-constant warnings in app compile; move to compile only if main bytecode really needs it. - - Verify with `./mvnw -pl opendaimon-spring-ai -am clean compile test dependency:analyze -DskipITs -DskipIT`. + - [x] `opendaimon-spring-ai` module cleanup + - Resolved previous analyzer warnings for Spring AI chat-memory autoconfig runtime glue and `com.h2database:h2:test`. + - Kept module-local ArchUnit dependencies with a targeted analyzer ignore for the JUnit Platform runtime engine. + - Verified with `./mvnw -pl opendaimon-spring-ai -am clean compile dependency:analyze -DskipTests -DskipITs -DskipIT`: dependency analyzer reports `No dependency problems found`. + - Verified module tests with `./mvnw -pl opendaimon-spring-ai -am test -Dtest='io.github.ngirchev.opendaimon.ai.springai.**.*Test' -Dsurefire.failIfNoSpecifiedTests=false -DskipITs -DskipIT`: 463 tests, 0 failures/errors, 1 skipped. - [x] `opendaimon-rest` module cleanup - Added REST-local `RestArchitectureTest` with layer, explicit-configuration, repository, DTO/model, and service/delivery boundary rules. - Added REST ArchUnit test dependencies and targeted analyzer ignore for the JUnit Platform engine. - Kept `org.hamcrest:hamcrest:test` because `SessionControllerContractTest` imports Hamcrest matchers directly. - Resolved previous `jackson-core` / `spring-beans` analyzer warnings through direct dependency cleanup. - Verified with `./mvnw -pl opendaimon-rest -am clean compile -DskipTests`, `./mvnw -pl opendaimon-rest -am test -Dtest=RestArchitectureTest -Dsurefire.failIfNoSpecifiedTests=false -DskipITs -DskipIT`, `./mvnw -pl opendaimon-rest -am dependency:analyze -DskipTests`, and `./mvnw -pl opendaimon-rest -am test -DskipITs -DskipIT`. - - [ ] `opendaimon-telegram` module cleanup - - Re-run tests after handler-test constructor patches. - - Confirm `com.github.ben-manes.caffeine:caffeine` is declared directly because `TelegramChatPacerImpl` imports it. - - Verify with `./mvnw -pl opendaimon-telegram -am clean compile test dependency:analyze -DskipITs -DskipIT`. + - [x] `opendaimon-telegram` module cleanup + - Re-ran tests after handler-test constructor patches. + - Confirmed `com.github.ben-manes.caffeine:caffeine` is declared directly because `TelegramChatPacerImpl` imports it. + - Verified with `./mvnw -pl opendaimon-telegram -am clean compile dependency:analyze -DskipTests -DskipITs -DskipIT`: dependency analyzer reports `No dependency problems found`. + - Verified module tests with `./mvnw -pl opendaimon-telegram -am clean test -Dtest='io.github.ngirchev.opendaimon.telegram.**.*Test' -Dsurefire.failIfNoSpecifiedTests=false -DskipITs -DskipIT`: 481 tests, 0 failures/errors, 19 skipped. - [x] `opendaimon-ui` and `opendaimon-gateway-mock` module cleanup - Run analyzer/enforcer per module and fix only local POM warnings. - - [ ] `opendaimon-app` ArchUnit verification + - [x] `opendaimon-app` ArchUnit verification - Run `./mvnw -pl opendaimon-app -am test -Dtest=ArchitectureTest -Dsurefire.failIfNoSpecifiedTests=false`. - Fix real boundary/layer violations in code; do not reintroduce frozen ArchUnit rules. + - Verified with `./mvnw -pl opendaimon-app -am test -Dtest=ArchitectureTest -Dsurefire.failIfNoSpecifiedTests=false`: `ArchitectureTest` passed (7 tests, 0 failures/errors/skipped). - [ ] Final reactor verification - Run `./mvnw clean compile`. - Run `./mvnw dependency:analyze -DskipTests`. diff --git a/TRADEMARKS.md b/TRADEMARKS.md new file mode 100644 index 00000000..b4e056c8 --- /dev/null +++ b/TRADEMARKS.md @@ -0,0 +1,18 @@ +# Trademarks + +The Apache License, Version 2.0 grants rights to use, copy, modify, and +redistribute the OpenDaimon software. It does not grant trademark rights. + +The names "OpenDaimon" and "OpenDaimon AI", the project logos, and associated +branding are trademarks or project identifiers of Nikolai Girchev. + +You may use the OpenDaimon name to truthfully refer to the original project, +compatible integrations, or unmodified distributions. + +You may not use the OpenDaimon name, logos, or branding in a way that suggests +that a modified version, hosted service, commercial product, or third-party +distribution is the official OpenDaimon project or is endorsed by Nikolai Girchev +without written permission. + +If you distribute a fork or modified version, use a distinct product name and +clearly state that it is derived from OpenDaimon. diff --git a/cli/package-lock.json b/cli/package-lock.json index e43b8dac..b8b162a2 100644 --- a/cli/package-lock.json +++ b/cli/package-lock.json @@ -7,7 +7,7 @@ "": { "name": "@ngirchev/open-daimon", "version": "1.0.0", - "license": "MIT", + "license": "Apache-2.0", "dependencies": { "@inquirer/prompts": "^7" }, diff --git a/cli/package.json b/cli/package.json index 22ee2988..291fef41 100644 --- a/cli/package.json +++ b/cli/package.json @@ -24,8 +24,8 @@ "openrouter", "ollama" ], - "author": "ngirchev", - "license": "MIT", + "author": "Nikolai Girchev", + "license": "Apache-2.0", "repository": { "type": "git", "url": "https://github.com/NGirchev/open-daimon" diff --git a/docs/team/archunit-rules.md b/docs/team/archunit-rules.md index f0c80fe1..95d63684 100644 --- a/docs/team/archunit-rules.md +++ b/docs/team/archunit-rules.md @@ -3,439 +3,144 @@ slug: archunit-rules title: "ArchUnit Architecture Rules" owner: ngirchev created: 2026-04-28 +updated: 2026-05-01 status: done base_branch: fsm --- -## §0 One-Line Summary +## Summary -Introduce ArchUnit-based tests enforcing the architectural invariants already documented in AGENTS.md. Minimum-rule first pass: no @Service/@Component (Spring stereotypes), no cyclic dependencies between opendaimon-* modules, services live in .service packages, implementations carry the Impl suffix. This is session 1 of 3 — followed later by /team dependency-cleanup and /team opendaimon-spring-boot-starter. - -## §1 Problem Statement - -The architectural invariants documented in `AGENTS.md` (Project Style Guide) are enforced today only by reviewer effort: - -- Library modules export beans through `@Bean` methods in `@Configuration` classes (no `@Service`/`@Component`) so the future `opendaimon-spring-boot-starter` can let downstream consumers override them via `@ConditionalOnMissingBean` and property toggles. -- The dependency graph between library modules forms a DAG — cycles would break Maven build ordering and downstream classpaths. - -Before publishing the public starter (a future `/team` session), we want executable, fast-failing tests that catch regressions. The project today already complies with both invariants. The risk this work mitigates is silent future regression. - -This is session 1 of 3 in the starter delivery roadmap: -1. /team archunit-rules (this session) — encode invariants as ArchUnit tests. -2. /team dependency-cleanup — `mvn dependency:analyze` sweep, declare all used deps explicitly. -3. /team opendaimon-spring-boot-starter — create the public starter module. - -## §2 Goals & Non-Goals - -Goals: -- G1. ArchUnit rule **R1** — classes in library-module packages must NOT be annotated with `@Service` or `@Component`. -- G2. ArchUnit rule **R2** — no cyclic dependencies between the four library modules: `opendaimon-common`, `opendaimon-spring-ai`, `opendaimon-telegram`, `opendaimon-rest`. -- G3. Tests run in default `mvn test` (Surefire, no profile gating, no `@Tag` exclusion). -- G4. Fail-fast on regression. Baseline today = 0 violations. - -Non-Goals: -- Rules beyond R1/R2 (Impl-suffix, layering, `*Service` naming) — deferred to a later session after baseline is green. -- Refactoring existing code (only point-fix if ArchUnit unexpectedly catches a violation; if >3 violations are found, escalate to user before fixing). -- New feature toggles, properties, or configuration knobs. -- Changes to `opendaimon-app`, `opendaimon-ui`, `opendaimon-gateway-mock` source — these modules are exempt from R1 and R2 by explicit user directive. -- Creation of a new Maven module for arch-tests (explicitly rejected). -- Publication of `opendaimon-spring-boot-starter` (separate session). -- Documentation refresh of `AGENTS.md` (the rules already exist there — this work just makes them executable). - -## §3 Stakeholders - -- Owner: ngirchev (project tech lead). -- Direct beneficiaries: contributors and AI agents working under the /team pipeline — invariants become executable, removing reliance on review-time heuristics. -- Indirect beneficiaries: downstream consumers of the future Maven Central artifacts — protected from regressions in cross-module dependency hygiene. - -## §4 Existing State (Explorer findings) - -Round B dispatched three parallel team-explorer agents. Findings: - -(a) Module roles -- `opendaimon-app` — runtime executable. Has `@SpringBootApplication`-like `Application` class at `io.github.ngirchev.opendaimon.Application`. Aggregates all other modules at compile scope. Exempt from R1/R2. -- `opendaimon-ui` — frontend module (per user directive). Contains some Java backend code under `io.github.ngirchev.opendaimon.ai.ui..` (controllers/config) but is treated as outside the rule scope. -- `opendaimon-gateway-mock` — Spring Boot auto-configuration library (`META-INF/spring/.../AutoConfiguration.imports`, `MockGatewayAutoConfig`). Used as compile-scope dep of `-app`. Exempt from R1/R2 per user directive ("просто моки"). -- `opendaimon-common`, `-spring-ai`, `-telegram`, `-rest` — library modules in scope of R1 and R2. - -(b) Test infrastructure of `opendaimon-app` -- Pre-existing `src/test/java`: single base class `AbstractContainerIT` in package `io.github.ngirchev.opendaimon.test`. -- `src/it/java` is added as an additional test-source by `build-helper-maven-plugin`; Failsafe picks up `**/*IT.java` in `verify` phase. -- Test-scoped dependencies (7): `spring-boot-starter-test`, `spring-boot-testcontainers`, `testcontainers`, `postgresql` (testcontainers), `junit-jupiter` (testcontainers), `mockwebserver` (okhttp3), `h2`. -- Surefire config in root `pluginManagement`: `forkCount=1`, `reuseForks=true`, `parallel=classes`, `threadCount=2`. Default include pattern `**/*Test.java`. -- The base Java package of `opendaimon-app` is `io.github.ngirchev.opendaimon` (no `.app` segment) — this is the package root that ArchUnit will analyse. - -(c) ArchUnit + JUnit 5 -- Library: `com.tngtech.archunit:archunit-junit5`. Latest stable: 1.4.2 (compatible with Java 21 and JUnit 5; auto-registers via ServiceLoader). -- Required `ImportOption`s: `DoNotIncludeTests` (drops `target/test-classes`), `DoNotIncludeJars` (excludes external jars; critical for performance and to keep analysis scoped to project classes). -- DSL for R1: `noClasses().that().resideInAnyPackage(...).should().beAnnotatedWith(Service.class).orShould().beAnnotatedWith(Component.class)`. -- DSL for R2: `slices().assignedFrom(SliceAssignment).should().beFreeOfCycles()` — `beFreeOfCycles()` is the correct operator (NOT `notDependOnEachOther()`, which forbids any inter-module reference and is too strict given a shared common module). - -(d) Package-root non-uniformity -Maven module names do NOT match Java package roots: -- `-common` → `io.github.ngirchev.opendaimon.common..` -- `-telegram` → `io.github.ngirchev.opendaimon.telegram..` -- `-rest` → `io.github.ngirchev.opendaimon.rest..` -- `-spring-ai` → `io.github.ngirchev.opendaimon.ai.springai..` (two segments, under `..ai..`) -- `-ui` → `io.github.ngirchev.opendaimon.ai.ui..` -- `-gateway-mock` → `io.github.ngirchev.opendaimon.ai.mock..` -- `-app` → `io.github.ngirchev.opendaimon` (Application.java directly in base) - -Implication: a naive `slices().matching("io.github.ngirchev.opendaimon.(*)..")` would collapse `-spring-ai`, `-ui`, `-gateway-mock` into a single "ai" slice. R2 therefore needs a custom `SliceAssignment` that maps package prefixes to Maven module names explicitly. - -(e) Current compliance baseline -- 0 `@Service` annotations in any library module. -- 0 `@Component` annotations in any library module. -- Two grep matches for `@Service` in `opendaimon-common/.../service/SummarizationService.java` and `ConversationThreadService.java` are JAVADOC TEXT explaining the no-`@Service` decision — not annotations. -- Conclusion: ArchUnit will pass green on first run; no fix-now action is required. - -## §5 Proposed Architecture - -(a) File layout -- One new test class: `opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java` (package `io.github.ngirchev.opendaimon.arch`). -- No new Maven module. -- No source code outside `opendaimon-app/src/test/`. - -(b) Class skeleton - -```java -@AnalyzeClasses( - packages = "io.github.ngirchev.opendaimon", - importOptions = { - ImportOption.DoNotIncludeTests.class, - ArchitectureTest.IncludeOpendaimonOnly.class - } -) -class ArchitectureTest { - - /** - * Admits exploded class files unconditionally and only those JAR entries - * whose URI contains "/opendaimon-" (our own multi-module JARs). - * Replaces ImportOption.DoNotIncludeJars: under `mvn verify` upstream - * sibling modules reach the `package` phase and are loaded as JARs, not - * exploded directories — DoNotIncludeJars filtered them out, leaving 0 - * classes in the four library-module package roots and tripping ArchUnit's - * `failOnEmptyShould=true` default. See §12(g). - */ - public static class IncludeOpendaimonOnly implements ImportOption { - @Override - public boolean includes(com.tngtech.archunit.core.importer.Location location) { - if (!location.contains(".jar")) { - return true; // exploded class file (target/classes) - } - return location.contains("/opendaimon-"); - } - } - - // R1 — see (c) - // R2 — see (d) -} -``` +OpenDaimon now has executable ArchUnit checks for the core Spring Boot library architecture: -> Note: `ImportOption.DoNotIncludeJars` is replaced by the project-local `IncludeOpendaimonOnly` filter. Without this fix, the rules pass under `mvn test` (sibling modules referenced as exploded `target/classes`) but fail under `mvn verify` (sibling modules packaged into JARs, then filtered out by `DoNotIncludeJars`). The custom filter keeps performance close to `DoNotIncludeJars` (third-party JARs still skipped) while keeping correctness across both lifecycles. - -(c) R1 — no component-discovery stereotypes in library modules - -```java -@ArchTest -static final ArchRule library_modules_use_no_service_or_component_stereotypes = - noClasses() - .that().resideInAnyPackage( - "io.github.ngirchev.opendaimon.common..", - "io.github.ngirchev.opendaimon.ai.springai..", - "io.github.ngirchev.opendaimon.telegram..", - "io.github.ngirchev.opendaimon.rest..") - .should().beAnnotatedWith(org.springframework.stereotype.Service.class) - .orShould().beAnnotatedWith(org.springframework.stereotype.Component.class) - .because("Library modules export beans via @Bean methods in @Configuration classes " - + "so the upcoming opendaimon-spring-boot-starter can let downstream " - + "applications override beans via @ConditionalOnMissingBean (AGENTS.md)."); - -@ArchTest -static final ArchRule library_modules_use_no_repository_classes = - noClasses() - .that().resideInAnyPackage( - "io.github.ngirchev.opendaimon.common..", - "io.github.ngirchev.opendaimon.ai.springai..", - "io.github.ngirchev.opendaimon.telegram..", - "io.github.ngirchev.opendaimon.rest..") - .and().areNotInterfaces() - .should().beAnnotatedWith(org.springframework.stereotype.Repository.class) - .because("@Repository is only allowed on Spring Data repository interfaces."); -``` +- `opendaimon-app` keeps the cross-module rules: no Spring component-discovery stereotypes in published library modules, no concrete `@Repository` classes, and no cyclic dependencies between `common`, `spring-ai`, `telegram`, and `rest`. +- `opendaimon-common` keeps common-module rules for stereotypes, configuration placement, property classes, service naming, implementation suffixes, and repository placement. +- `opendaimon-rest`, `opendaimon-telegram`, and `opendaimon-spring-ai` now each have module-local layer rules. -Notes: -- `@RestController`, `@Repository`, `@Configuration`, `@ConfigurationProperties`, `@Bean` are NOT forbidden — they are the legitimate Spring Boot library style. -- Concrete `@Repository` classes are forbidden; Spring Data repository interfaces may carry `@Repository`, although the annotation is not required when `@EnableJpaRepositories` scans the package. -- `noClasses().should().beAnnotatedWith(...)` checks the LITERAL annotation, not Spring meta-annotations. - -(d) R2 — no cyclic dependencies between library modules - -```java -private static final SliceAssignment LIBRARY_MODULES = new SliceAssignment() { - @Override - public SliceIdentifier getIdentifierOf(JavaClass cls) { - String pkg = cls.getPackageName(); - if (pkg.startsWith("io.github.ngirchev.opendaimon.common")) return SliceIdentifier.of("common"); - if (pkg.startsWith("io.github.ngirchev.opendaimon.telegram")) return SliceIdentifier.of("telegram"); - if (pkg.startsWith("io.github.ngirchev.opendaimon.rest")) return SliceIdentifier.of("rest"); - if (pkg.startsWith("io.github.ngirchev.opendaimon.ai.springai")) return SliceIdentifier.of("spring-ai"); - return SliceIdentifier.ignore(); - } - @Override - public String getDescription() { return "library modules"; } -}; - -@ArchTest -static final ArchRule library_modules_have_no_cyclic_dependencies = - slices().assignedFrom(LIBRARY_MODULES) - .should().beFreeOfCycles() - .because("Cycles between library modules would break Maven publication " - + "ordering and downstream classpath resolution."); -``` +The rules encode the project style from `AGENTS.md`: library modules are consumed by downstream applications, so bean creation is explicit through configuration classes, configuration properties are kept in `config`, and service layers must not leak controller, handler, DTO, or transport concerns inward. -Notes: -- `-app`, `-ui`, `-gateway-mock` map to `SliceIdentifier.ignore()` and are excluded from cycle analysis. -- `beFreeOfCycles()` allows any DAG topology (including the expected `common` ← all-others). It only fails on actual cycles. - -(e) Maven changes -- Root `pom.xml`: add property `1.4.2` in the existing `` block, alphabetically near other `*.version` entries. -- `opendaimon-app/pom.xml`: add the dependency at the END of the test-deps section (group 5 per the comment header): - -```xml - - com.tngtech.archunit - archunit-junit5 - ${archunit.version} - test - -``` +## Scope -- No changes to any other module's `pom.xml`. - -(f) Test naming and Surefire pickup -- Class name `ArchitectureTest` matches Surefire's default `**/*Test.java` include pattern → runs in standard `mvn test`. -- Class is NOT named `*IT` → Failsafe ignores it. -- No `@Tag` annotations → not affected by the `fixture` profile. - -## §6 Data Model Changes - -None. No DB migrations, no entity changes, no schema work. - -## §7 API / Interface Changes - -None. This work touches only test code and one root pom.xml `` entry plus one `` in `opendaimon-app/pom.xml`. No public API of any module changes. No method signatures, no class moves. - -## §8 Open Questions (architectural) - -None blocking. The following items are explicitly resolved: - -- Test placement → `opendaimon-app/src/test/java/.../arch/ArchitectureTest.java`. -- Gate → default `mvn test`. -- Fix-policy on existing violations → fix-now (baseline already 0; no action). -- Rule scope → R1 + R2 only; R3/R4 deferred. -- ArchUnit-junit5 version → 1.4.2. -- Slice strategy → custom `SliceAssignment` with explicit module mapping. -- Module exemptions → `-app`, `-ui`, `-gateway-mock` exempt from both R1 and R2. - -Implementation-detail items (not blocking architecture): -- Exact `` insertion point and exact `` ordering in test deps — handled by Phase 5 developer. -- Imports of `org.springframework.stereotype.Service`/`Component` and `com.tngtech.archunit.*` types — handled by Phase 5 developer. - -## §9 Requirements - -- [x] **REQ-1** — `archunit-junit5` test dependency available in `opendaimon-app` test classpath. - - Acceptance: `./mvnw dependency:tree -pl opendaimon-app -Dincludes=com.tngtech.archunit:archunit-junit5` lists the artifact at version `1.4.2` with `scope=test`. Version is sourced from `${archunit.version}` in root `pom.xml` ``. - - Verified by: — - -- [x] **REQ-2** — R1: classes in the four library-module packages are not annotated with `@Service` or `@Component`, and concrete classes are not annotated with `@Repository`. - - Acceptance: `ArchitectureTest#library_modules_use_no_service_or_component_stereotypes` PASSES on current main; FAILS within the same test method when a synthetic `@org.springframework.stereotype.Service`-annotated class is added under any of `io.github.ngirchev.opendaimon.{common,ai.springai,telegram,rest}..`. `ArchitectureTest#library_modules_use_no_repository_classes` PASSES while allowing Spring Data repository interfaces. Negative paths are verified by QA via temporary fixture, not by leaving a violator in the tree. - - Verified by: — - -- [x] **REQ-3** — R2: no cyclic dependencies between library modules `common`, `spring-ai`, `telegram`, `rest`. - - Acceptance: `ArchitectureTest#library_modules_have_no_cyclic_dependencies` PASSES on current main. Custom `SliceAssignment` maps `..opendaimon.common..`, `..opendaimon.ai.springai..`, `..opendaimon.telegram..`, `..opendaimon.rest..` to four named slices and returns `SliceIdentifier.ignore()` for `..opendaimon.ai.ui..`, `..opendaimon.ai.mock..`, and the bare `..opendaimon` package (Application root). - - Verified by: — - -- [x] **REQ-4** — Tests run in the default `mvn test` lifecycle without profile or tag activation. - - Acceptance: `./mvnw test -pl opendaimon-app -am` lists `ArchitectureTest` in the Surefire test report. The class is named `ArchitectureTest` (Surefire's default `**/*Test.java` pattern), is NOT named `*IT` (so Failsafe ignores it), and carries no `@Tag` (so the `fixture` profile does not affect it). - - Verified by: — - -- [x] **REQ-5** — Baseline green: implementation introduces zero changes under any module's `src/main/` and tests pass on first run. - - Acceptance: After Phase 5 completion, `git diff --name-only origin/master..HEAD -- '**/src/main/**'` returns empty. `./mvnw test -pl opendaimon-app -am -Dtest=ArchitectureTest` exits 0. - - Verified by: — - -## §10 Implementation Plan (Tasks) - -- [x] **TASK-1** — Maven dependency wiring for ArchUnit - - Depends on: — - - Assignee slot: serial - - Files: - - `pom.xml` - - `opendaimon-app/pom.xml` - - Acceptance: - 1. Root `pom.xml` `` block contains a single new line `1.4.2`, placed alphabetically among existing `*.version` entries. No other property changes, no reordering of unrelated entries. - 2. `opendaimon-app/pom.xml` test-deps section (group 5 per the inline comment) contains a new dependency `com.tngtech.archunit:archunit-junit5` referencing `${archunit.version}` with `test`. Inserted as the LAST entry of group 5; no other test deps reordered. - 3. `./mvnw clean compile test-compile -pl opendaimon-app -am` exits 0. - 4. `./mvnw dependency:tree -pl opendaimon-app -Dincludes=com.tngtech.archunit:archunit-junit5` shows the dependency in test scope at version 1.4.2. - - Unit tests to add: none (this TASK is build-config only). - - Notes: see §5(e). Do NOT add `archunit-junit5` to root `` — it is an `opendaimon-app`-local test concern, not a shared library contract. Do NOT add the dep to any other module's `pom.xml`. - -- [x] **TASK-2** — `ArchitectureTest` implementation (R1 + R2) - - Depends on: TASK-1 - - Assignee slot: serial - - Files: - - `opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java` - - Acceptance: - 1. New class `io.github.ngirchev.opendaimon.arch.ArchitectureTest` exists, package-private (no `public`), annotated with `@AnalyzeClasses(packages = "io.github.ngirchev.opendaimon", importOptions = {ImportOption.DoNotIncludeTests.class, ImportOption.DoNotIncludeJars.class})`. - 2. Contains a `private static final SliceAssignment LIBRARY_MODULES = ...` exactly as specified in §5(d), mapping the four library-module package roots and returning `SliceIdentifier.ignore()` for everything else. - 3. Contains `@ArchTest static final ArchRule library_modules_use_no_service_or_component_stereotypes = ...` per §5(c), referencing `org.springframework.stereotype.Service` and `org.springframework.stereotype.Component` literally (NOT `@Component`-derived stereotypes like `@RestController`/`@Repository`), plus `library_modules_use_no_repository_classes` to ban concrete `@Repository` classes while allowing Spring Data repository interfaces. - 4. Contains `@ArchTest static final ArchRule library_modules_have_no_cyclic_dependencies = ...` per §5(d), using `slices().assignedFrom(LIBRARY_MODULES).should().beFreeOfCycles()`. - 5. Both rules carry `.because(...)` strings citing the AGENTS.md rationale (R1: starter override pattern; R2: Maven publication ordering). - 6. `./mvnw test -pl opendaimon-app -am -Dtest=ArchitectureTest` exits 0 with both `@ArchTest` rules executed (visible in Surefire `` entries). - - Unit tests to add: the `@ArchTest` static fields ARE the tests — no separate `*Test.java` companion needed. - - Notes: see §§5(b), 5(c), 5(d). Imports needed: `com.tngtech.archunit.core.domain.JavaClass`, `com.tngtech.archunit.junit.AnalyzeClasses`, `com.tngtech.archunit.junit.ArchTest`, `com.tngtech.archunit.core.importer.ImportOption`, `com.tngtech.archunit.lang.ArchRule`, `com.tngtech.archunit.library.dependencies.SliceAssignment`, `com.tngtech.archunit.library.dependencies.SliceIdentifier`, plus static imports `com.tngtech.archunit.core.domain.JavaClass.Predicates.*` if used, and `com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses`, `com.tngtech.archunit.library.dependencies.SlicesRuleDefinition.slices`. Do NOT use `@ArchIgnore`. Do NOT add a meta-test that intentionally violates the rules. - -- [x] **TASK-3** — Lifecycle fix: replace `DoNotIncludeJars` with `IncludeOpendaimonOnly` - - Depends on: TASK-2 - - Assignee slot: serial - - Files: - - `opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java` - - Acceptance: - 1. Inside `ArchitectureTest`, add `public static class IncludeOpendaimonOnly implements ImportOption` exactly as specified in §5(b). Include the Javadoc citing §12(g). - 2. Replace `ImportOption.DoNotIncludeJars.class` with `ArchitectureTest.IncludeOpendaimonOnly.class` in the `@AnalyzeClasses` `importOptions = {...}` array. - 3. Add the import `com.tngtech.archunit.core.importer.Location` if not already present. - 4. `./mvnw test -pl opendaimon-app -am -Dtest=ArchitectureTest` exits 0 — both `library_modules_*` rules PASS, both check >0 classes (no "failed to check any classes" assertion). - 5. `./mvnw clean verify -pl opendaimon-app -am -Pfixture` exits 0 — Surefire phase runs `ArchitectureTest` against packaged sibling JARs; both rules PASS. This is the original regression case from the Phase 7 QA. - 6. ArchitectureTest runtime in both lifecycles stays under ~5 seconds (custom filter must NOT cause it to scan all third-party JARs). - - Unit tests to add: none (the `@ArchTest` static fields are the tests; no separate companion). - - Notes: see §5(b) updated code block and §12(g) regression analysis. Do NOT touch any pom.xml, do NOT modify any other file. Do NOT reintroduce `DoNotIncludeJars`. Do NOT use `allowEmptyShould(true)` as a workaround — that is an anti-pattern (silent failure mode). - -(§10.1 Optional dependency DAG) - -```mermaid -graph LR - TASK1[TASK-1: Maven wiring] --> TASK2[TASK-2: ArchitectureTest] -``` +In scope: -NON-OVERLAP CHECK (orchestrator-confirmed before dispatch): -- TASK-1 Files: pom.xml, opendaimon-app/pom.xml -- TASK-2 Files: opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java -- Intersection: empty. ✅ +- `opendaimon-common` +- `opendaimon-spring-ai` +- `opendaimon-telegram` +- `opendaimon-rest` +- cross-module checks from `opendaimon-app` -## §11 Q&A Log +Out of scope: -TBD +- `opendaimon-ui` +- `opendaimon-gateway-mock` +- application runtime wiring beyond the existing cross-module `ArchitectureTest` -## §12 Risk Register +## Rule Set -Findings from Phase 6 explorer audit (one explorer, full diff vs. parent branch `fsm`). Severity reclassified by orchestrator per `code-review.md` thresholds. +### Cross-Module Rules -(a) MEDIUM — `archunit-junit5` insertion point appears non-final in `opendaimon-app/pom.xml` -- Original explorer rating: HIGH. Reclassified to MEDIUM by orchestrator: explorer itself notes "functionally harmless"; HIGH is reserved for bugs / significant quality issues per `code-review.md`. -- Description: `archunit-junit5` (lines 171–176) is followed by `pdfbox` and `pdfbox-io` (lines 178–187). The archunit dep IS positioned correctly relative to all test-scoped dependencies (it sits immediately after `mockwebserver`, the last test-scoped entry). The visual ambiguity arises from a PRE-EXISTING structural defect — see (b) below. -- Action: none in this session. No code move would improve clarity without addressing (b), which is out of scope for `/team archunit-rules`. -- Resolution path: addressed in `/team dependency-cleanup` (session 2 of 3). +File: `opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java` -(b) MEDIUM — Pre-existing pdfbox mis-placement [DEFERRED — out of scope] -- Description: in `opendaimon-app/pom.xml`, dependencies `pdfbox` (lines 178–182) and `pdfbox-io` (lines 183–187) lack `test` (default = `compile`) but live under the comment block that visually belongs to the test-deps section. They should either (1) carry `test` to match the comment, or (2) move above the test-deps section into group 4 (utility/runtime). Pre-existing in `master` — not introduced by this feature. -- Action: defer to `/team dependency-cleanup`. Do NOT fix here — that would extend the scope of this session. -- Reference: explorer audit, finding #4. +- Published library modules must not use `@Service` or `@Component`. +- Concrete classes must not use `@Repository`; Spring Data repository interfaces remain allowed. +- Library modules must not form package-level dependency cycles. +- `IncludeOpendaimonOnly` keeps ArchUnit import behavior stable across both `mvn test` and `mvn verify -Pfixture` by allowing exploded classes and only project-owned `opendaimon-*` JARs. -(c) MEDIUM — `archunit.version` placement in root `` is not strictly alphabetical -- Description: `` (root `pom.xml:102`) is placed in the test-version sub-cluster between `` and ``. Strict alphabetical ordering across the entire `` block would put it earlier (before `byte-buddy`, `caffeine`). The current placement co-locates it with related test-version entries (`okhttp`, `mockito`, `testcontainers`). -- Action: accepted as-is. Co-location with peer test-version entries is a defensible local convention. No fix. -- Reference: explorer audit, MEDIUM finding. +### Common Rules -(d) LOW — Rule field naming uses snake_case -- Description: `library_modules_use_no_service_or_component_stereotypes`, `library_modules_use_no_repository_classes`, and `library_modules_have_no_cyclic_dependencies` use underscore-separated names rather than the project-wide `shouldDoSomethingWhenCondition` convention. -- Action: accepted. ArchUnit's `static final ArchRule` fields conventionally use descriptive snake_case (per ArchUnit user-guide examples). The project test-method convention does not apply to fields. -- Reference: explorer audit, LOW finding. +File: `opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/common/arch/CommonArchitectureTest.java` -(e) LOW — Inline FQN references for `Service.class` / `Component.class` -- Description: `org.springframework.stereotype.Service.class` and `Component.class` referenced via fully-qualified names inline (`ArchitectureTest.java:58-59`) rather than as `import` statements at the top. -- Action: accepted. Stylistic preference; no functional impact, no readability concern given the rule is short. -- Reference: explorer audit, LOW finding. +- No `@Service` or `@Component`. +- Configuration classes and `@Bean` methods stay under `common.config`. +- `@ConfigurationProperties` classes stay under `common.config`, end with `Properties`, and use validation. +- Services live under `common.service`, service implementations end with `Impl`, and interfaces stay interface-only. +- Repository access is limited to repository and service layers. -(g) HIGH (resolved by TASK-3) — `DoNotIncludeJars` lifecycle-dependent failure -- Description: under `mvn verify -Pfixture` the original `ImportOption.DoNotIncludeJars` filtered out our own packaged sibling JARs (`opendaimon-common-1.0.0-SNAPSHOT.jar`, etc.) because Maven `package` phase ran before Surefire. Result: ArchitectureTest's `that().resideInAnyPackage(...)` matcher saw 0 classes in all four library packages, and ArchUnit's default `failOnEmptyShould=true` raised AssertionError on both `@ArchTest` rules. The rule logic itself is correct — only the ImportOption choice was wrong. -- Detected by: Phase 7 QA (`./mvnw clean verify -pl opendaimon-app -am -Pfixture`). -- Resolution: TASK-3 introduces `ArchitectureTest.IncludeOpendaimonOnly implements ImportOption` admitting exploded class files unconditionally and JARs only when URI contains `/opendaimon-`. See §5(b) updated code block. -- Lesson learned: ArchUnit `ImportOption` filters interact with Maven lifecycle phase. Any future `ImportOption` choice must be validated under BOTH `mvn test` and `mvn verify -Pfixture` before declaring DONE. Phase 1 explorer #3 flagged a related risk (siblings unbuilt → empty analysis) but missed the inverse case (siblings packaged → filtered out). Add lifecycle-coverage to the explorer checklist for future ArchUnit work. +### REST Rules -§12 STATUS — no open CRITICAL or HIGH findings (the HIGH finding (g) is being resolved by TASK-3 in a Phase-5-revisit loop; QA will re-run after TASK-3 ticks). +File: `opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/arch/RestArchitectureTest.java` -## §13 Definition of Done +- No `@Service` or `@Component`. +- No concrete `@Repository` classes. +- `@Bean`, `@Configuration`, and `@AutoConfiguration` classes stay under `rest.config`. +- `@ConfigurationProperties` classes stay under `rest.config`, end with `Properties`, and use validation. +- `@RestController` classes stay under `rest.controller`. +- `@ControllerAdvice` and `@RestControllerAdvice` classes stay under `rest.exception`. +- Repository access is limited to config, repository, and service layers. +- `rest.service..` does not depend on `rest.dto..` or `rest.handler..`. -All five REQs verified by team-qa-tester after TASK-3 remediation. Both lifecycle modes green. +Implementation cleanup required for these rules: -| REQ | Verifying Command | Result | -|---|---|---| -| REQ-1 | `./mvnw dependency:tree -pl opendaimon-app -am -Dincludes=com.tngtech.archunit:archunit-junit5` | PASS — `com.tngtech.archunit:archunit-junit5:jar:1.4.2:test` listed | -| REQ-2 | `./mvnw test -pl opendaimon-app -am -Dtest=ArchitectureTest` (`library_modules_use_no_service_or_component_stereotypes`, `library_modules_use_no_repository_classes`) | PASS — 3.046s under `mvn test`; 2.44s under `mvn verify -Pfixture` | -| REQ-3 | `./mvnw test -pl opendaimon-app -am -Dtest=ArchitectureTest` (`library_modules_have_no_cyclic_dependencies`) | PASS — 0.136s under `mvn test`; 0.132s under `mvn verify -Pfixture` | -| REQ-4 | `./mvnw test -pl opendaimon-app -am` (no `-Dtest`, no profile) — Surefire picks up `*Test.java` automatically, no `@Tag` filtering | PASS — `ArchitectureTest` runs in default `mvn test` lifecycle, 2 tests / 0 failures | -| REQ-5 | `git diff --name-only HEAD -- '**/src/main/**'` + `git ls-files --others --exclude-standard \| grep '/src/main/'` | PASS — both commands return empty; zero `src/main/` changes in any module | +- `RestChatCommand` and `RestChatCommandType` moved from `rest.handler` to `rest.command`. +- REST service return types were split into internal service models under `rest.service.model`. +- Controllers now map internal service models to public DTOs at the boundary. -Anti-regression checks: -- Full `opendaimon-app` Surefire suite: BUILD SUCCESS in 32.810s. -- Fixture suite (`mvn clean verify -pl opendaimon-app -am -Pfixture`): BUILD SUCCESS in 01:05 min, ArchitectureTest 2.576s, both rules executed against packaged opendaimon-* sibling JARs without `failOnEmptyShould` trip. +### Telegram Rules -Implementation summary: -- 3 production files touched: `pom.xml` (1 property added), `opendaimon-app/pom.xml` (1 test-dep added), `opendaimon-app/src/test/java/io/github/ngirchev/opendaimon/arch/ArchitectureTest.java` (created, 1 lifecycle fix applied). -- 0 changes under any `src/main/` of any module. -- 0 new Maven modules; 0 new feature toggles; 0 changes to existing `*AutoConfig` classes. +File: `opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/arch/TelegramArchitectureTest.java` -Status: ready for `/commit` (handled outside the /team pipeline per AGENTS.md "no auto-commit" rule). +- No `@Service` or `@Component`. +- No concrete `@Repository` classes. +- `@Bean`, `@Configuration`, and `@AutoConfiguration` classes stay under `telegram.config`. +- `@ConfigurationProperties` classes stay under `telegram.config`, end with `Properties`, and use validation. +- Repository access is limited to config, repository, and service layers. +- `telegram.service..` does not depend on `telegram.command.handler..`. -## §14 Activity Log +Implementation cleanup required for these rules: -- 2026-04-28T00:00:00Z TASK-1 completed by team-developer: archunit.version=1.4.2 in root pom.xml, archunit-junit5 test dep in opendaimon-app/pom.xml. Both acceptance checks (mvn compile + dependency:tree) green. -- 2026-04-28T00:01:00Z TASK-2 completed by team-developer: ArchitectureTest.java created at opendaimon-app/src/test/java/.../arch/. Both @ArchTest rules executed and PASS on current main (R1: 2.571s, R2: 0.138s, total 2.713s). Zero changes under src/main/. -- 2026-04-28T00:02:00Z Phase 6 verification: 1 explorer audited TASK-1 + TASK-2 against §10 Files: globs. Original ratings: 1 HIGH, 1 MEDIUM, 2 LOW. Orchestrator reclassified HIGH → MEDIUM (functionally harmless per explorer's own note). -- 2026-04-28T00:03:00Z Pre-existing pdfbox mis-placement in opendaimon-app/pom.xml deferred to /team dependency-cleanup (session 2 of 3). No code move performed — archunit-junit5 already positioned correctly relative to test-scoped deps. -- 2026-04-28T00:04:00Z Phase 7 QA returned BLOCKED: production regression on REQ-2 / REQ-3 under `mvn verify -Pfixture`. Mechanism: `ImportOption.DoNotIncludeJars` filters packaged opendaimon-* JARs once Maven advances to `package` phase; ArchitectureTest's `failOnEmptyShould=true` default trips. Detected via `./mvnw clean verify -pl opendaimon-app -am -Pfixture`. -- 2026-04-28T00:05:00Z TASK-3 authored to resolve §12(g): replace `DoNotIncludeJars` with project-local `IncludeOpendaimonOnly` ImportOption. Pipeline returns to Phase 5 for TASK-3, then re-runs Phase 6 (verification) and Phase 7 (QA). -- 2026-04-28T00:06:00Z TASK-3 completed by team-developer: ArchitectureTest now uses IncludeOpendaimonOnly ImportOption. Both lifecycles verified — mvn test PASS (2.661s), mvn clean verify -Pfixture PASS (ArchitectureTest 2.487s, full reactor 01:09 min). §12(g) regression resolved. -- 2026-04-28T00:07:00Z Phase 7 QA re-run after TASK-3: ALL 5 REQs PASS. UNIT RUN: PASS, FIXTURE RUN: PASS, MAPPING UPDATE: no. §12(g) regression closed. §13 Definition of Done populated with verification table. -- 2026-04-28T00:08:00Z Phase 8 closure: §14 closure notes authored, frontmatter status → done, base_branch metadata corrected to `fsm` (parent branch). Pipeline complete; orchestrator hands off to user for /commit. +- Telegram message FSM types moved from `telegram.command.handler.impl.fsm` to `telegram.service.fsm`. +- `TelegramMessageSender` and `TelegramDeliveryFailedException` moved to `telegram.service`. +- `TelegramSupportedCommandProvider` moved to `telegram.command`. ---- +### Spring AI Rules + +File: `opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/arch/SpringAIArchitectureTest.java` + +- No `@Service` or `@Component`. +- No concrete `@Repository` classes. +- `@Bean`, `@Configuration`, and `@AutoConfiguration` classes stay under `ai.springai.config`. +- `@ConfigurationProperties` classes stay under `ai.springai.config`, end with `Properties`, and use validation. +- Runtime slices are checked for cycles across `advisor`, `agent`, `embedding`, `memory`, `rag`, `rest`, `retry`, `service`, and `tool`. + +Implementation cleanup required for these rules: + +- `AgentAutoConfig` moved from `ai.springai.agent` to `ai.springai.config`. +- `AgentProperties` moved from `ai.springai.agent` to `ai.springai.config`. +- `OpenRouterModelsProperties` moved from `ai.springai.retry` to `ai.springai.config`. +- `AutoConfiguration.imports` now references `ai.springai.config.AgentAutoConfig`. -#### Closure Notes (Phase 8) +## Maven Wiring -- **Use-case docs to update**: none. This feature does not touch any `docs/usecases/*.md` — ArchUnit rules are infrastructure tests, not user-facing behavior. -- **Module docs to update**: none. No `*_MODULE.md` documentation exists for `opendaimon-app/arch/` (test infrastructure), and `AGENTS.md` already documents the architectural invariants textually. The new `ArchitectureTest.java` is self-documenting via its class-level Javadoc and inline `.because(...)` rule descriptions. -- **Suggested commit type** (per `.claude/rules/git-workflow.md`): `test` — primary deliverable is a test class enforcing architectural invariants; secondary build-config additions in two `pom.xml` files support that test. -- **Suggested commit subject**: `test: add ArchUnit rules for stereotypes and module cycles` -- **Suggested commit body** (HEREDOC-friendly): +Root `pom.xml` owns the ArchUnit version through `archunit.version`. +The modules with local ArchUnit tests declare ArchUnit test dependencies directly: + +- `opendaimon-app` +- `opendaimon-common` +- `opendaimon-rest` +- `opendaimon-telegram` +- `opendaimon-spring-ai` + +Modules that use `archunit-junit5-engine` only through test discovery list it in the Maven dependency plugin's `ignoredUsedUndeclaredDependencies`, matching the existing `opendaimon-common` pattern. + +## Verification + +Commands used during this cleanup: + +```bash +./mvnw -pl opendaimon-rest -am test -DskipITs -DskipIT +./mvnw -pl opendaimon-telegram -am test -DskipITs -DskipIT +./mvnw -pl opendaimon-spring-ai -am test -DskipITs -DskipIT ``` -Add ArchitectureTest in opendaimon-app/src/test/java/.../arch/ enforcing -two invariants from AGENTS.md as executable JUnit 5 / ArchUnit rules: - - R1: classes in library-module packages (common, ai.springai, telegram, - rest) must not be annotated with @Service or @Component — beans - must be exported via @Bean methods so the future - opendaimon-spring-boot-starter can let downstream consumers - override them via @ConditionalOnMissingBean. - - R2: no cyclic dependencies between the four library modules — checked - via custom SliceAssignment that maps each Maven module to its - package root and ignores opendaimon-app, -ui, -gateway-mock. - -Custom IncludeOpendaimonOnly ImportOption admits exploded class files -and only opendaimon-* JARs, so rules pass under both `mvn test` -(siblings as target/classes) and `mvn verify -Pfixture` (siblings as -packaged JARs). Replaces ImportOption.DoNotIncludeJars which silently -filtered our own JARs in the verify lifecycle. - -Baseline: 0 violations on current main. Tests run in default `mvn test` -in ~3 seconds, no profile gating, no @Tag. - -Maven changes: - - root pom.xml: 1.4.2 - - opendaimon-app/pom.xml: archunit-junit5 in test scope - -Session 1 of 3 in starter delivery roadmap; sessions 2 and 3 are -/team dependency-cleanup and /team opendaimon-spring-boot-starter. + +The final cleanup pass should also run: + +```bash +./mvnw -pl opendaimon-app -am test -Dtest=ArchitectureTest -Dsurefire.failIfNoSpecifiedTests=false -DskipITs -DskipIT +./mvnw -pl opendaimon-rest -am dependency:analyze -DskipITs -DskipIT +./mvnw -pl opendaimon-telegram -am dependency:analyze -DskipITs -DskipIT +./mvnw -pl opendaimon-spring-ai -am dependency:analyze -DskipITs -DskipIT ``` + +## Status + +Done when all module-local ArchUnit suites and dependency analysis checks pass, and no references remain to the old package locations for moved REST, Telegram, and Spring AI types. diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/TelegramMessageHandlerActionsTestWiring.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/TelegramMessageHandlerActionsTestWiring.java index 588269ba..ba6b1885 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/TelegramMessageHandlerActionsTestWiring.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/TelegramMessageHandlerActionsTestWiring.java @@ -7,12 +7,12 @@ import io.github.ngirchev.opendaimon.common.service.OpenDaimonMessageService; import io.github.ngirchev.opendaimon.telegram.TelegramBot; import io.github.ngirchev.opendaimon.telegram.command.handler.impl.MessageTelegramCommandHandler; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerContext; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerEvent; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerFsmFactory; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerState; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageHandlerActions; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageSender; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerContext; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerEvent; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerFsmFactory; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerState; +import io.github.ngirchev.opendaimon.telegram.service.fsm.TelegramMessageHandlerActions; +import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageSender; import io.github.ngirchev.opendaimon.telegram.config.TelegramProperties; import io.github.ngirchev.opendaimon.telegram.service.ChatSettingsService; import io.github.ngirchev.opendaimon.telegram.service.PersistentKeyboardService; diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/config/AgentAutoConfigSmokeIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/config/AgentAutoConfigSmokeIT.java index c8e196e8..57f3b15c 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/config/AgentAutoConfigSmokeIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/config/AgentAutoConfigSmokeIT.java @@ -1,6 +1,6 @@ package io.github.ngirchev.opendaimon.it.config; -import io.github.ngirchev.opendaimon.ai.springai.agent.AgentAutoConfig; +import io.github.ngirchev.opendaimon.ai.springai.config.AgentAutoConfig; import io.github.ngirchev.opendaimon.ai.springai.agent.PlanAndExecuteAgentExecutor; import io.github.ngirchev.opendaimon.ai.springai.agent.ReActAgentExecutor; import io.github.ngirchev.opendaimon.ai.springai.agent.SimpleChainExecutor; diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/config/CoreAutoConfigSmokeIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/config/CoreAutoConfigSmokeIT.java index 2fdc51a9..7358dd26 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/config/CoreAutoConfigSmokeIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/config/CoreAutoConfigSmokeIT.java @@ -38,7 +38,7 @@ "org.springframework.ai.model.openai.autoconfigure.OpenAiEmbeddingAutoConfiguration," + "org.springframework.ai.model.openai.autoconfigure.OpenAiImageAutoConfiguration," + "io.github.ngirchev.opendaimon.ai.springai.config.SpringAIAutoConfig," + - "io.github.ngirchev.opendaimon.ai.springai.agent.AgentAutoConfig," + + "io.github.ngirchev.opendaimon.ai.springai.config.AgentAutoConfig," + "io.github.ngirchev.opendaimon.bulkhead.config.BulkHeadAutoConfig," + "io.github.ngirchev.opendaimon.telegram.config.TelegramAutoConfig", "open-daimon.common.bulkhead.enabled=false", diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/fixture/config/TelegramFixtureConfig.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/fixture/config/TelegramFixtureConfig.java index 2f8d4fe7..ad244852 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/fixture/config/TelegramFixtureConfig.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/fixture/config/TelegramFixtureConfig.java @@ -30,19 +30,11 @@ import io.github.ngirchev.opendaimon.telegram.TelegramBot; import io.github.ngirchev.opendaimon.it.TelegramMessageHandlerActionsTestWiring; import io.github.ngirchev.opendaimon.telegram.command.handler.impl.MessageTelegramCommandHandler; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerContext; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerEvent; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerFsmFactory; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerState; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageHandlerActions; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageSender; -import io.github.ngirchev.fsm.impl.extended.ExDomainFsm; import io.github.ngirchev.opendaimon.telegram.config.TelegramProperties; import io.github.ngirchev.opendaimon.telegram.repository.TelegramUserRepository; import io.github.ngirchev.opendaimon.telegram.repository.TelegramUserSessionRepository; import io.github.ngirchev.opendaimon.telegram.service.PersistentKeyboardService; import io.github.ngirchev.opendaimon.telegram.service.ReplyImageAttachmentService; -import io.github.ngirchev.opendaimon.telegram.service.TelegramAgentStreamView; import io.github.ngirchev.opendaimon.telegram.service.TelegramChatPacerImpl; import io.github.ngirchev.opendaimon.telegram.service.TelegramFileService; import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageService; @@ -237,10 +229,12 @@ public TelegramUserService telegramUserService( @Bean public ObjectProvider storagePropertiesProvider() { - @SuppressWarnings("unchecked") - ObjectProvider provider = mock(ObjectProvider.class); - when(provider.getIfAvailable()).thenReturn(null); - return provider; + return new ObjectProvider<>() { + @Override + public StorageProperties getIfAvailable() { + return null; + } + }; } @Bean diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/telegram/TelegramMockGatewayIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/telegram/TelegramMockGatewayIT.java index c99f4b93..36f6a82c 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/telegram/TelegramMockGatewayIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/telegram/TelegramMockGatewayIT.java @@ -58,12 +58,12 @@ import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; import io.github.ngirchev.opendaimon.it.TelegramMessageHandlerActionsTestWiring; import io.github.ngirchev.opendaimon.telegram.command.handler.impl.MessageTelegramCommandHandler; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerContext; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerEvent; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerFsmFactory; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerState; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageHandlerActions; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageSender; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerContext; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerEvent; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerFsmFactory; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerState; +import io.github.ngirchev.opendaimon.telegram.service.fsm.TelegramMessageHandlerActions; +import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageSender; import io.github.ngirchev.fsm.impl.extended.ExDomainFsm; import io.github.ngirchev.opendaimon.telegram.config.TelegramFlywayConfig; import io.github.ngirchev.opendaimon.telegram.config.TelegramJpaConfig; diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/telegram/command/handler/MessageTelegramCommandHandlerIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/telegram/command/handler/MessageTelegramCommandHandlerIT.java index f5b3a047..2aa4c92a 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/telegram/command/handler/MessageTelegramCommandHandlerIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/telegram/command/handler/MessageTelegramCommandHandlerIT.java @@ -3,7 +3,6 @@ import io.github.ngirchev.opendaimon.it.ITTestConfiguration; import io.github.ngirchev.opendaimon.telegram.service.PersistentKeyboardService; import io.github.ngirchev.opendaimon.telegram.service.ReplyImageAttachmentService; -import io.github.ngirchev.opendaimon.telegram.service.TelegramAgentStreamView; import io.github.ngirchev.opendaimon.telegram.service.TelegramChatPacerImpl; import io.github.ngirchev.opendaimon.telegram.service.TelegramFileService; import io.github.ngirchev.opendaimon.common.service.ChatOwnerLookup; @@ -49,13 +48,6 @@ import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; import io.github.ngirchev.opendaimon.it.TelegramMessageHandlerActionsTestWiring; import io.github.ngirchev.opendaimon.telegram.command.handler.impl.MessageTelegramCommandHandler; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerContext; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerEvent; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerFsmFactory; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerState; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageHandlerActions; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageSender; -import io.github.ngirchev.fsm.impl.extended.ExDomainFsm; import io.github.ngirchev.opendaimon.telegram.config.TelegramFlywayConfig; import io.github.ngirchev.opendaimon.telegram.config.TelegramJpaConfig; import io.github.ngirchev.opendaimon.common.storage.config.StorageProperties; @@ -243,9 +235,12 @@ public TelegramUserService telegramUserService( @Bean @Primary public ObjectProvider storagePropertiesProvider() { - ObjectProvider provider = mock(ObjectProvider.class); - when(provider.getIfAvailable()).thenReturn(null); - return provider; + return new ObjectProvider<>() { + @Override + public StorageProperties getIfAvailable() { + return null; + } + }; } @Bean diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatCommand.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/command/RestChatCommand.java similarity index 70% rename from opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatCommand.java rename to opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/command/RestChatCommand.java index c4401147..7ffe1f56 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatCommand.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/command/RestChatCommand.java @@ -1,11 +1,13 @@ -package io.github.ngirchev.opendaimon.rest.handler; +package io.github.ngirchev.opendaimon.rest.command; import jakarta.servlet.http.HttpServletRequest; import io.github.ngirchev.opendaimon.common.command.IChatCommand; -import io.github.ngirchev.opendaimon.rest.dto.ChatRequestDto; public record RestChatCommand( - ChatRequestDto chatRequestDto, + String message, + String assistantRole, + String model, + String email, RestChatCommandType commandType, HttpServletRequest request, Long userId @@ -18,11 +20,11 @@ public Long userId() { @Override public String userText() { - return chatRequestDto != null ? chatRequestDto.message() : null; + return message; } @Override public boolean stream() { return commandType == RestChatCommandType.STREAM; } -} \ No newline at end of file +} diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatCommandType.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/command/RestChatCommandType.java similarity index 74% rename from opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatCommandType.java rename to opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/command/RestChatCommandType.java index ccf99e56..24c5f176 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatCommandType.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/command/RestChatCommandType.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.rest.handler; +package io.github.ngirchev.opendaimon.rest.command; import io.github.ngirchev.opendaimon.common.command.ICommandType; diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/controller/AdminConversationController.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/controller/AdminConversationController.java index 8ce2c9ca..da199a79 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/controller/AdminConversationController.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/controller/AdminConversationController.java @@ -1,11 +1,19 @@ package io.github.ngirchev.opendaimon.rest.controller; import io.github.ngirchev.opendaimon.common.model.ThreadScopeKind; +import io.github.ngirchev.opendaimon.rest.dto.admin.AttachmentRefDto; import io.github.ngirchev.opendaimon.rest.dto.admin.ConversationSummaryDto; import io.github.ngirchev.opendaimon.rest.dto.admin.MessageDetailDto; import io.github.ngirchev.opendaimon.rest.dto.admin.MessageSummaryDto; import io.github.ngirchev.opendaimon.rest.dto.admin.PageResponseDto; +import io.github.ngirchev.opendaimon.rest.dto.admin.UserSummaryDto; import io.github.ngirchev.opendaimon.rest.service.AdminQueryService; +import io.github.ngirchev.opendaimon.rest.service.model.AdminAttachmentRef; +import io.github.ngirchev.opendaimon.rest.service.model.AdminConversationSummary; +import io.github.ngirchev.opendaimon.rest.service.model.AdminMessageDetail; +import io.github.ngirchev.opendaimon.rest.service.model.AdminMessageSummary; +import io.github.ngirchev.opendaimon.rest.service.model.AdminPageResponse; +import io.github.ngirchev.opendaimon.rest.service.model.AdminUserSummary; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; @@ -53,24 +61,103 @@ public ResponseEntity> listConversations boundedPage, boundedSize == 0 ? DEFAULT_PAGE_SIZE : boundedSize, Sort.by(Sort.Direction.DESC, "lastActivityAt")); - return ResponseEntity.ok(adminQueryService.listConversations(userId, scopeKind, isActive, pageable)); + return ResponseEntity.ok(toConversationPageDto(adminQueryService.listConversations(userId, scopeKind, isActive, pageable))); } @GetMapping("/conversations/{id}") @Operation(summary = "Get conversation metadata") public ResponseEntity getConversation(@PathVariable Long id) { - return ResponseEntity.ok(adminQueryService.getConversation(id)); + return ResponseEntity.ok(toDto(adminQueryService.getConversation(id))); } @GetMapping("/conversations/{id}/messages") @Operation(summary = "List messages of a conversation", description = "Sorted by sequenceNumber asc") public ResponseEntity> listMessages(@PathVariable Long id) { - return ResponseEntity.ok(adminQueryService.listMessages(id)); + return ResponseEntity.ok(adminQueryService.listMessages(id).stream() + .map(AdminConversationController::toDto) + .toList()); } @GetMapping("/messages/{id}") @Operation(summary = "Get single message with attachments metadata") public ResponseEntity getMessage(@PathVariable Long id) { - return ResponseEntity.ok(adminQueryService.getMessage(id)); + return ResponseEntity.ok(toDto(adminQueryService.getMessage(id))); + } + + private static PageResponseDto toConversationPageDto( + AdminPageResponse page) { + return new PageResponseDto<>( + page.content().stream().map(AdminConversationController::toDto).toList(), + page.page(), + page.size(), + page.totalElements(), + page.totalPages()); + } + + private static ConversationSummaryDto toDto(AdminConversationSummary summary) { + return new ConversationSummaryDto( + summary.id(), + summary.threadKey(), + summary.title(), + summary.scopeKind(), + summary.scopeId(), + summary.totalMessages(), + summary.totalTokens(), + summary.isActive(), + summary.lastActivityAt(), + summary.createdAt(), + toDto(summary.user())); + } + + private static MessageSummaryDto toDto(AdminMessageSummary summary) { + return new MessageSummaryDto( + summary.id(), + summary.sequenceNumber(), + summary.role(), + summary.requestType(), + summary.status(), + summary.contentPreview(), + summary.attachmentCount(), + summary.createdAt()); + } + + private static MessageDetailDto toDto(AdminMessageDetail detail) { + return new MessageDetailDto( + detail.id(), + detail.threadId(), + detail.sequenceNumber(), + detail.role(), + detail.content(), + detail.requestType(), + detail.status(), + detail.serviceName(), + detail.tokenCount(), + detail.processingTimeMs(), + detail.errorMessage(), + detail.telegramMessageId(), + detail.createdAt(), + detail.attachments().stream().map(AdminConversationController::toDto).toList(), + detail.metadata(), + detail.responseData(), + toDto(detail.user())); + } + + private static AttachmentRefDto toDto(AdminAttachmentRef ref) { + return new AttachmentRefDto(ref.storageKey(), ref.mimeType(), ref.filename(), ref.expiresAt()); + } + + private static UserSummaryDto toDto(AdminUserSummary user) { + if (user == null) { + return null; + } + return new UserSummaryDto( + user.id(), + user.userType(), + user.username(), + user.firstName(), + user.lastName(), + user.emailOrTelegramId(), + user.isAdmin(), + user.isBlocked()); } } diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/controller/AdminUserController.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/controller/AdminUserController.java index a76a4338..d87577e3 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/controller/AdminUserController.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/controller/AdminUserController.java @@ -3,6 +3,8 @@ import io.github.ngirchev.opendaimon.rest.dto.admin.PageResponseDto; import io.github.ngirchev.opendaimon.rest.dto.admin.UserSummaryDto; import io.github.ngirchev.opendaimon.rest.service.AdminQueryService; +import io.github.ngirchev.opendaimon.rest.service.model.AdminPageResponse; +import io.github.ngirchev.opendaimon.rest.service.model.AdminUserSummary; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; @@ -38,6 +40,27 @@ public ResponseEntity> listUsers( int boundedSize = Math.min(Math.max(size, 1), MAX_PAGE_SIZE); int boundedPage = Math.max(page, 0); PageRequest pageable = PageRequest.of(boundedPage, boundedSize, Sort.by("id")); - return ResponseEntity.ok(adminQueryService.listUsers(search, pageable)); + return ResponseEntity.ok(toDto(adminQueryService.listUsers(search, pageable))); + } + + private static PageResponseDto toDto(AdminPageResponse page) { + return new PageResponseDto<>( + page.content().stream().map(AdminUserController::toDto).toList(), + page.page(), + page.size(), + page.totalElements(), + page.totalPages()); + } + + private static UserSummaryDto toDto(AdminUserSummary user) { + return new UserSummaryDto( + user.id(), + user.userType(), + user.username(), + user.firstName(), + user.lastName(), + user.emailOrTelegramId(), + user.isAdmin(), + user.isBlocked()); } } diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/controller/SessionController.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/controller/SessionController.java index cf8b4069..cab7bce0 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/controller/SessionController.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/controller/SessionController.java @@ -16,8 +16,10 @@ import io.github.ngirchev.opendaimon.rest.exception.UnauthorizedException; import io.github.ngirchev.opendaimon.rest.service.ChatService; import io.github.ngirchev.opendaimon.rest.service.RestAuthorizationService; +import io.github.ngirchev.opendaimon.rest.service.model.ChatMessage; +import io.github.ngirchev.opendaimon.rest.service.model.ChatResponse; +import io.github.ngirchev.opendaimon.rest.service.model.ChatSession; -import java.time.Duration; import java.util.List; /** @@ -44,13 +46,12 @@ public ResponseEntity> sendMessageToNewChat( HttpServletRequest httpRequest, HttpSession session) { String email = getEmailFromSessionOrRequest(session, request.email(), httpRequest.getLocale().getLanguage()); - return ResponseEntity.ok( - chatService.sendMessageToNewChat( + ChatResponse response = chatService.sendMessageToNewChat( request.message(), restAuthorizationService.authorize(email, httpRequest.getLocale().getLanguage()), httpRequest, - false) - ); + false); + return ResponseEntity.ok(toDto(response)); } @PostMapping("/{sessionId}") @@ -61,13 +62,13 @@ public ResponseEntity> sendMessage( HttpServletRequest httpRequest, HttpSession session) { String email = getEmailFromSessionOrRequest(session, request.email(), httpRequest.getLocale().getLanguage()); - return ResponseEntity.ok(chatService.sendMessage( + ChatResponse response = chatService.sendMessage( sessionId, request.message(), restAuthorizationService.authorize(email, httpRequest.getLocale().getLanguage()), httpRequest, - false) - ); + false); + return ResponseEntity.ok(toDto(response)); } // @PostMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE) @@ -94,7 +95,7 @@ public Flux> sendMessageToNewChatStream( HttpSession session) { String email = getEmailFromSessionOrRequest(session, request.email(), httpRequest.getLocale().getLanguage()); var user = restAuthorizationService.authorize(email, httpRequest.getLocale().getLanguage()); - ChatResponseDto> response = chatService.sendMessageToNewChat(request.message(), user, httpRequest, true); + ChatResponse> response = chatService.sendMessageToNewChat(request.message(), user, httpRequest, true); String sessionId = response.sessionId(); // Send sessionId in first event with type "metadata" ServerSentEvent sessionEvent = ServerSentEvent.builder() @@ -119,7 +120,7 @@ public Flux> sendMessageStream( HttpSession session) { String email = getEmailFromSessionOrRequest(session, request.email(), httpRequest.getLocale().getLanguage()); var user = restAuthorizationService.authorize(email, httpRequest.getLocale().getLanguage()); - ChatResponseDto> response = chatService.sendMessage(sessionId, request.message(), user, httpRequest, true); + ChatResponse> response = chatService.sendMessage(sessionId, request.message(), user, httpRequest, true); // Do not use delayElements - send data as soon as it arrives return response.message() // Convert to SSE @@ -134,7 +135,9 @@ public ResponseEntity> getSessions( HttpServletRequest httpRequest) { String userEmail = getEmailFromSessionOrRequest(session, email, httpRequest.getLocale().getLanguage()); var user = restAuthorizationService.authorize(userEmail, httpRequest.getLocale().getLanguage()); - return ResponseEntity.ok(chatService.getSessions(user)); + return ResponseEntity.ok(chatService.getSessions(user).stream() + .map(SessionController::toDto) + .toList()); } @GetMapping("/{sessionId}/messages") @@ -146,7 +149,9 @@ public ResponseEntity getSessionMessages( HttpServletRequest httpRequest) { String userEmail = getEmailFromSessionOrRequest(session, email, httpRequest.getLocale().getLanguage()); var user = restAuthorizationService.authorize(userEmail, httpRequest.getLocale().getLanguage()); - List messages = chatService.getChatHistory(sessionId, user); + List messages = chatService.getChatHistory(sessionId, user).stream() + .map(SessionController::toDto) + .toList(); return ResponseEntity.ok(new ChatHistoryResponseDto(sessionId, messages)); } @@ -182,5 +187,16 @@ private String getEmailFromSessionOrRequest(HttpSession session, String emailFro } throw new UnauthorizedException(messageLocalizationService.getMessage("rest.auth.email.required", languageCode)); } -} + private static ChatResponseDto toDto(ChatResponse response) { + return new ChatResponseDto<>(response.message(), response.sessionId()); + } + + private static ChatSessionDto toDto(ChatSession session) { + return new ChatSessionDto(session.sessionId(), session.name(), session.createdAt()); + } + + private static ChatMessageDto toDto(ChatMessage message) { + return new ChatMessageDto(message.role(), message.content()); + } +} diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatHandlerSupport.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatHandlerSupport.java index c6d7daca..f6162631 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatHandlerSupport.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatHandlerSupport.java @@ -10,6 +10,7 @@ import io.github.ngirchev.opendaimon.common.service.OpenDaimonMessageService; import io.github.ngirchev.opendaimon.common.service.AIUtils; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommand; import io.github.ngirchev.opendaimon.common.SupportedLanguages; diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatMessageCommandHandler.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatMessageCommandHandler.java index 3d09b832..d62ca7b3 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatMessageCommandHandler.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatMessageCommandHandler.java @@ -16,6 +16,8 @@ import io.github.ngirchev.opendaimon.common.service.*; import io.github.ngirchev.opendaimon.bulkhead.exception.AccessDeniedException; import io.github.ngirchev.opendaimon.common.exception.UserMessageTooLongException; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommand; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommandType; import io.github.ngirchev.opendaimon.rest.model.RestUser; import io.github.ngirchev.opendaimon.rest.service.RestMessageService; import io.github.ngirchev.opendaimon.rest.service.RestUserService; @@ -31,7 +33,8 @@ @Slf4j @RequiredArgsConstructor public class RestChatMessageCommandHandler implements - ICommandHandler { + ICommandHandler { private final RestMessageService restMessageService; private final RestUserService restUserService; @@ -61,12 +64,12 @@ public String handle(RestChatCommand command) { String lang = RestChatHandlerSupport.getRequestLanguage(command); RestUser user = restUserService.findById(command.userId()) .orElseThrow(() -> new RuntimeException(support.getMessageLocalizationService().getMessage("rest.user.not.found", lang, command.userId()))); - String assistantRoleContent = command.chatRequestDto().assistantRole() != null - ? command.chatRequestDto().assistantRole() + String assistantRoleContent = command.assistantRole() != null + ? command.assistantRole() : null; userMessage = restMessageService.saveUserMessage( user, - command.chatRequestDto().message(), + command.message(), RequestType.TEXT, assistantRoleContent, command.request()); diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatStreamMessageCommandHandler.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatStreamMessageCommandHandler.java index 54a97919..b37f7b74 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatStreamMessageCommandHandler.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/handler/RestChatStreamMessageCommandHandler.java @@ -16,6 +16,8 @@ import io.github.ngirchev.opendaimon.common.command.ICommandHandler; import io.github.ngirchev.opendaimon.common.model.*; import io.github.ngirchev.opendaimon.common.service.*; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommand; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommandType; import io.github.ngirchev.opendaimon.rest.model.RestUser; import io.github.ngirchev.opendaimon.rest.service.RestMessageService; import io.github.ngirchev.opendaimon.rest.service.RestUserService; @@ -32,7 +34,8 @@ @Slf4j @RequiredArgsConstructor public class RestChatStreamMessageCommandHandler implements - ICommandHandler> { + ICommandHandler> { private final RestMessageService restMessageService; private final RestUserService restUserService; @@ -62,12 +65,12 @@ public Flux handle(RestChatCommand command) { String lang = RestChatHandlerSupport.getRequestLanguage(command); RestUser user = restUserService.findById(command.userId()) .orElseThrow(() -> new RuntimeException(support.getMessageLocalizationService().getMessage("rest.user.not.found", lang, command.userId()))); - String assistantRoleContent = command.chatRequestDto().assistantRole() != null - ? command.chatRequestDto().assistantRole() + String assistantRoleContent = command.assistantRole() != null + ? command.assistantRole() : null; userMessage = restMessageService.saveUserMessage( user, - command.chatRequestDto().message(), + command.message(), RequestType.TEXT, assistantRoleContent, command.request()); diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/AdminQueryService.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/AdminQueryService.java index bc6cb37f..41dc1c6e 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/AdminQueryService.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/AdminQueryService.java @@ -5,16 +5,16 @@ import io.github.ngirchev.opendaimon.common.model.ThreadScopeKind; import io.github.ngirchev.opendaimon.common.model.User; import io.github.ngirchev.opendaimon.common.repository.OpenDaimonMessageRepository; -import io.github.ngirchev.opendaimon.rest.dto.admin.AttachmentRefDto; -import io.github.ngirchev.opendaimon.rest.dto.admin.ConversationSummaryDto; -import io.github.ngirchev.opendaimon.rest.dto.admin.MessageDetailDto; -import io.github.ngirchev.opendaimon.rest.dto.admin.MessageSummaryDto; -import io.github.ngirchev.opendaimon.rest.dto.admin.PageResponseDto; -import io.github.ngirchev.opendaimon.rest.dto.admin.UserSummaryDto; import io.github.ngirchev.opendaimon.rest.exception.UnauthorizedException; import io.github.ngirchev.opendaimon.rest.model.RestUser; import io.github.ngirchev.opendaimon.rest.repository.AdminConversationRepository; import io.github.ngirchev.opendaimon.rest.repository.AdminUserRepository; +import io.github.ngirchev.opendaimon.rest.service.model.AdminAttachmentRef; +import io.github.ngirchev.opendaimon.rest.service.model.AdminConversationSummary; +import io.github.ngirchev.opendaimon.rest.service.model.AdminMessageDetail; +import io.github.ngirchev.opendaimon.rest.service.model.AdminMessageSummary; +import io.github.ngirchev.opendaimon.rest.service.model.AdminPageResponse; +import io.github.ngirchev.opendaimon.rest.service.model.AdminUserSummary; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; @@ -45,26 +45,26 @@ public class AdminQueryService { private final OpenDaimonMessageRepository messageRepository; @Transactional(readOnly = true) - public PageResponseDto listConversations( + public AdminPageResponse listConversations( Long userId, ThreadScopeKind scopeKind, Boolean isActive, Pageable pageable) { Page page = adminConversationRepository .findAllWithFilters(userId, scopeKind, isActive, pageable); - return PageResponseDto.from(page.map(this::toConversationSummary)); + return AdminPageResponse.from(page.map(this::toConversationSummary)); } @Transactional(readOnly = true) - public ConversationSummaryDto getConversation(Long threadId) { + public AdminConversationSummary getConversation(Long threadId) { ConversationThread thread = adminConversationRepository.findByIdWithUser(threadId) .orElseThrow(() -> new UnauthorizedException("Conversation not found: " + threadId)); return toConversationSummary(thread); } @Transactional(readOnly = true) - public List listMessages(Long threadId) { + public List listMessages(Long threadId) { ConversationThread thread = adminConversationRepository.findByIdWithUser(threadId) .orElseThrow(() -> new UnauthorizedException("Conversation not found: " + threadId)); List messages = messageRepository.findByThreadOrderBySequenceNumberAsc(thread); - List result = new ArrayList<>(messages.size()); + List result = new ArrayList<>(messages.size()); for (OpenDaimonMessage m : messages) { result.add(toMessageSummary(m)); } @@ -72,20 +72,20 @@ public List listMessages(Long threadId) { } @Transactional(readOnly = true) - public MessageDetailDto getMessage(Long messageId) { + public AdminMessageDetail getMessage(Long messageId) { OpenDaimonMessage message = messageRepository.findById(messageId) .orElseThrow(() -> new UnauthorizedException("Message not found: " + messageId)); return toMessageDetail(message); } @Transactional(readOnly = true) - public PageResponseDto listUsers(String search, Pageable pageable) { + public AdminPageResponse listUsers(String search, Pageable pageable) { Page page = adminUserRepository.searchAll(search, pageable); - return PageResponseDto.from(page.map(this::toUserSummary)); + return AdminPageResponse.from(page.map(this::toUserSummary)); } - private ConversationSummaryDto toConversationSummary(ConversationThread t) { - return new ConversationSummaryDto( + private AdminConversationSummary toConversationSummary(ConversationThread t) { + return new AdminConversationSummary( t.getId(), t.getThreadKey(), t.getTitle(), @@ -100,8 +100,8 @@ private ConversationSummaryDto toConversationSummary(ConversationThread t) { ); } - private MessageSummaryDto toMessageSummary(OpenDaimonMessage m) { - return new MessageSummaryDto( + private AdminMessageSummary toMessageSummary(OpenDaimonMessage m) { + return new AdminMessageSummary( m.getId(), m.getSequenceNumber(), m.getRole() != null ? m.getRole().name() : null, @@ -113,8 +113,8 @@ private MessageSummaryDto toMessageSummary(OpenDaimonMessage m) { ); } - private MessageDetailDto toMessageDetail(OpenDaimonMessage m) { - return new MessageDetailDto( + private AdminMessageDetail toMessageDetail(OpenDaimonMessage m) { + return new AdminMessageDetail( m.getId(), m.getThread() != null ? m.getThread().getId() : null, m.getSequenceNumber(), @@ -135,13 +135,13 @@ private MessageDetailDto toMessageDetail(OpenDaimonMessage m) { ); } - private UserSummaryDto toUserSummary(User user) { + private AdminUserSummary toUserSummary(User user) { if (user == null) { return null; } String discriminator = resolveUserType(user); String identity = resolveIdentity(user); - return new UserSummaryDto( + return new AdminUserSummary( user.getId(), discriminator, user.getUsername(), @@ -186,17 +186,17 @@ private String invokeTelegramId(User user) { } } - private List toAttachmentRefs(List> raw) { + private List toAttachmentRefs(List> raw) { if (raw == null || raw.isEmpty()) { return List.of(); } - List refs = new ArrayList<>(raw.size()); + List refs = new ArrayList<>(raw.size()); for (Map entry : raw) { String storageKey = asString(entry.get(ATTACH_KEY_STORAGE)); if (storageKey == null) { continue; } - refs.add(new AttachmentRefDto( + refs.add(new AdminAttachmentRef( storageKey, asString(entry.get(ATTACH_KEY_MIME)), asString(entry.get(ATTACH_KEY_FILENAME)), diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/ChatService.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/ChatService.java index 10f0ed7f..833304bb 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/ChatService.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/ChatService.java @@ -13,14 +13,13 @@ import io.github.ngirchev.opendaimon.bulkhead.service.IUserPriorityService; import io.github.ngirchev.opendaimon.common.service.CommandSyncService; import io.github.ngirchev.opendaimon.common.service.ConversationThreadService; -import io.github.ngirchev.opendaimon.rest.handler.RestChatCommand; -import io.github.ngirchev.opendaimon.rest.handler.RestChatCommandType; -import io.github.ngirchev.opendaimon.rest.dto.ChatRequestDto; -import io.github.ngirchev.opendaimon.rest.dto.ChatResponseDto; -import io.github.ngirchev.opendaimon.rest.dto.ChatSessionDto; -import io.github.ngirchev.opendaimon.rest.dto.ChatMessageDto; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommand; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommandType; import io.github.ngirchev.opendaimon.rest.model.RestUser; import io.github.ngirchev.opendaimon.rest.exception.UnauthorizedException; +import io.github.ngirchev.opendaimon.rest.service.model.ChatMessage; +import io.github.ngirchev.opendaimon.rest.service.model.ChatResponse; +import io.github.ngirchev.opendaimon.rest.service.model.ChatSession; import java.util.List; import java.util.stream.Collectors; @@ -45,7 +44,7 @@ public class ChatService { * Sends message to new chat (creates new session) */ @Transactional - public ChatResponseDto sendMessageToNewChat(String message, RestUser user, HttpServletRequest request, boolean isStream) { + public ChatResponse sendMessageToNewChat(String message, RestUser user, HttpServletRequest request, boolean isStream) { // Close current active thread (if any) threadRepository.findMostRecentActiveThread(user) .ifPresent(conversationThreadService::closeThread); @@ -54,7 +53,7 @@ public ChatResponseDto sendMessageToNewChat(String message, RestUser user ConversationThread thread = conversationThreadService.createNewThread(user); // Send message - return new ChatResponseDto<>( + return new ChatResponse<>( sendMessageInternal(thread.getThreadKey(), message, user, request, isStream), thread.getThreadKey() ); @@ -64,7 +63,7 @@ public ChatResponseDto sendMessageToNewChat(String message, RestUser user * Sends message to existing session */ @Transactional - public ChatResponseDto sendMessage(String sessionId, String message, RestUser user, HttpServletRequest request, boolean isStream) { + public ChatResponse sendMessage(String sessionId, String message, RestUser user, HttpServletRequest request, boolean isStream) { ConversationThread thread = getThreadBySessionId(sessionId); // Verify thread belongs to user @@ -76,7 +75,7 @@ public ChatResponseDto sendMessage(String sessionId, String message, Rest conversationThreadService.activateThread(user, thread); // Send message - return new ChatResponseDto<>( + return new ChatResponse<>( sendMessageInternal(thread.getThreadKey(), message, user, request, isStream), thread.getThreadKey() ); @@ -87,9 +86,11 @@ public ChatResponseDto sendMessage(String sessionId, String message, Rest */ private T sendMessageInternal(String sessionId, String message, RestUser user, HttpServletRequest request, boolean isStream) { // Create ChatRequest and send via existing handler - ChatRequestDto chatRequestDto = new ChatRequestDto(message, null, null, user.getEmail()); RestChatCommand command = new RestChatCommand( - chatRequestDto, + message, + null, + null, + user.getEmail(), isStream ? RestChatCommandType.STREAM : RestChatCommandType.MESSAGE, request, user.getId() @@ -102,11 +103,11 @@ private T sendMessageInternal(String sessionId, String message, RestUser use * Gets list of all user sessions */ @Transactional(readOnly = true) - public List getSessions(RestUser user) { + public List getSessions(RestUser user) { List threads = threadRepository.findByUserOrderByLastActivityAtDesc(user); return threads.stream() - .map(thread -> new ChatSessionDto( + .map(thread -> new ChatSession( thread.getThreadKey(), thread.getTitle() != null ? thread.getTitle() : "Untitled", thread.getCreatedAt() @@ -118,7 +119,7 @@ public List getSessions(RestUser user) { * Gets message history for session */ @Transactional(readOnly = true) - public List getChatHistory(String sessionId, RestUser user) { + public List getChatHistory(String sessionId, RestUser user) { ConversationThread thread = getThreadBySessionId(sessionId); // Verify thread belongs to user @@ -130,7 +131,7 @@ public List getChatHistory(String sessionId, RestUser user) { return messages.stream() .filter(msg -> msg.getRole() != MessageRole.SYSTEM) // Exclude system messages - .map(msg -> new ChatMessageDto( + .map(msg -> new ChatMessage( msg.getRole().name(), msg.getContent() )) @@ -168,4 +169,3 @@ private UserPriority getUserPriority(Long userId) { return userPriorityService.getUserPriority(userId); } } - diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminAttachmentRef.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminAttachmentRef.java new file mode 100644 index 00000000..05320626 --- /dev/null +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminAttachmentRef.java @@ -0,0 +1,11 @@ +package io.github.ngirchev.opendaimon.rest.service.model; + +import java.time.OffsetDateTime; + +public record AdminAttachmentRef( + String storageKey, + String mimeType, + String filename, + OffsetDateTime expiresAt +) { +} diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminConversationSummary.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminConversationSummary.java new file mode 100644 index 00000000..18099ef5 --- /dev/null +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminConversationSummary.java @@ -0,0 +1,18 @@ +package io.github.ngirchev.opendaimon.rest.service.model; + +import java.time.OffsetDateTime; + +public record AdminConversationSummary( + Long id, + String threadKey, + String title, + String scopeKind, + Long scopeId, + Integer totalMessages, + Long totalTokens, + Boolean isActive, + OffsetDateTime lastActivityAt, + OffsetDateTime createdAt, + AdminUserSummary user +) { +} diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminMessageDetail.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminMessageDetail.java new file mode 100644 index 00000000..a87eb376 --- /dev/null +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminMessageDetail.java @@ -0,0 +1,26 @@ +package io.github.ngirchev.opendaimon.rest.service.model; + +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Map; + +public record AdminMessageDetail( + Long id, + Long threadId, + Integer sequenceNumber, + String role, + String content, + String requestType, + String status, + String serviceName, + Integer tokenCount, + Integer processingTimeMs, + String errorMessage, + Long telegramMessageId, + OffsetDateTime createdAt, + List attachments, + Map metadata, + Map responseData, + AdminUserSummary user +) { +} diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminMessageSummary.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminMessageSummary.java new file mode 100644 index 00000000..106eafe0 --- /dev/null +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminMessageSummary.java @@ -0,0 +1,15 @@ +package io.github.ngirchev.opendaimon.rest.service.model; + +import java.time.OffsetDateTime; + +public record AdminMessageSummary( + Long id, + Integer sequenceNumber, + String role, + String requestType, + String status, + String contentPreview, + int attachmentCount, + OffsetDateTime createdAt +) { +} diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminPageResponse.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminPageResponse.java new file mode 100644 index 00000000..9a09b09f --- /dev/null +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminPageResponse.java @@ -0,0 +1,23 @@ +package io.github.ngirchev.opendaimon.rest.service.model; + +import org.springframework.data.domain.Page; + +import java.util.List; + +public record AdminPageResponse( + List content, + int page, + int size, + long totalElements, + int totalPages +) { + public static AdminPageResponse from(Page page) { + return new AdminPageResponse<>( + page.getContent(), + page.getNumber(), + page.getSize(), + page.getTotalElements(), + page.getTotalPages() + ); + } +} diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminUserSummary.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminUserSummary.java new file mode 100644 index 00000000..d59d5121 --- /dev/null +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/AdminUserSummary.java @@ -0,0 +1,13 @@ +package io.github.ngirchev.opendaimon.rest.service.model; + +public record AdminUserSummary( + Long id, + String userType, + String username, + String firstName, + String lastName, + String emailOrTelegramId, + Boolean isAdmin, + Boolean isBlocked +) { +} diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/ChatMessage.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/ChatMessage.java new file mode 100644 index 00000000..7edd0b3e --- /dev/null +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/ChatMessage.java @@ -0,0 +1,4 @@ +package io.github.ngirchev.opendaimon.rest.service.model; + +public record ChatMessage(String role, String content) { +} diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/ChatResponse.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/ChatResponse.java new file mode 100644 index 00000000..fa5d9fa7 --- /dev/null +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/ChatResponse.java @@ -0,0 +1,4 @@ +package io.github.ngirchev.opendaimon.rest.service.model; + +public record ChatResponse(T message, String sessionId) { +} diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/ChatSession.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/ChatSession.java new file mode 100644 index 00000000..b4f4a35c --- /dev/null +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/model/ChatSession.java @@ -0,0 +1,6 @@ +package io.github.ngirchev.opendaimon.rest.service.model; + +import java.time.OffsetDateTime; + +public record ChatSession(String sessionId, String name, OffsetDateTime createdAt) { +} diff --git a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/arch/RestArchitectureTest.java b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/arch/RestArchitectureTest.java index b6acf0e7..19617aa1 100644 --- a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/arch/RestArchitectureTest.java +++ b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/arch/RestArchitectureTest.java @@ -4,15 +4,10 @@ import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.methods; import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; -import com.tngtech.archunit.core.domain.Dependency; -import com.tngtech.archunit.core.domain.JavaClass; import com.tngtech.archunit.core.importer.ImportOption; import com.tngtech.archunit.junit.AnalyzeClasses; import com.tngtech.archunit.junit.ArchTest; -import com.tngtech.archunit.lang.ArchCondition; import com.tngtech.archunit.lang.ArchRule; -import com.tngtech.archunit.lang.ConditionEvents; -import com.tngtech.archunit.lang.SimpleConditionEvent; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -21,8 +16,9 @@ import org.springframework.stereotype.Repository; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; - -import java.util.Set; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.RestControllerAdvice; @AnalyzeClasses( packages = "io.github.ngirchev.opendaimon.rest", @@ -33,153 +29,75 @@ ) class RestArchitectureTest { - private static final String REST_PACKAGE = "io.github.ngirchev.opendaimon.rest"; - private static final String REST_MODULE_PACKAGE = REST_PACKAGE + ".."; - private static final String REST_CONFIG_PACKAGE = REST_PACKAGE + ".config.."; - private static final String REST_CONTROLLER_PACKAGE = REST_PACKAGE + ".controller.."; - private static final String REST_DTO_PACKAGE = REST_PACKAGE + ".dto.."; - private static final String REST_HANDLER_PACKAGE = REST_PACKAGE + ".handler.."; - private static final String REST_MODEL_PACKAGE = REST_PACKAGE + ".model.."; - private static final String REST_REPOSITORY_PACKAGE = REST_PACKAGE + ".repository.."; - private static final String REST_SERVICE_PACKAGE = REST_PACKAGE + ".service.."; - - private static final String REST_CONTROLLER_PACKAGE_PREFIX = REST_PACKAGE + ".controller"; - private static final String REST_HANDLER_PACKAGE_PREFIX = REST_PACKAGE + ".handler"; - - private static final String CHAT_SERVICE = REST_PACKAGE + ".service.ChatService"; - private static final Set CHAT_SERVICE_COMMAND_BRIDGE_TYPES = Set.of( - REST_PACKAGE + ".handler.RestChatCommand", - REST_PACKAGE + ".handler.RestChatCommandType" - ); - - private static final ArchCondition HAVE_REST_CONFIGURATION_PREFIX = - new ArchCondition<>("have an open-daimon.rest configuration prefix") { - @Override - public void check(JavaClass item, ConditionEvents events) { - ConfigurationProperties annotation = item.getAnnotationOfType(ConfigurationProperties.class); - String prefix = annotation.prefix().isBlank() ? annotation.value() : annotation.prefix(); - if (!prefix.startsWith("open-daimon.rest")) { - events.add(SimpleConditionEvent.violated( - item, - item.getName() + " uses configuration prefix '" + prefix + "'")); - } - } - }; - - private static final ArchCondition HAVE_NO_REST_DELIVERY_DEPENDENCIES_EXCEPT_COMMAND_BRIDGE = - new ArchCondition<>("not depend on REST delivery classes except the ChatService command bridge") { - @Override - public void check(JavaClass item, ConditionEvents events) { - item.getDirectDependenciesFromSelf().stream() - .map(Dependency::getTargetClass) - .filter(RestArchitectureTest::isRestDeliveryClass) - .filter(targetClass -> !isAllowedCommandBridge(item, targetClass)) - .forEach(targetClass -> events.add(SimpleConditionEvent.violated( - item, - item.getName() + " depends on delivery class " + targetClass.getName()))); - } - }; - @ArchTest - static final ArchRule rest_module_uses_no_service_or_component_stereotypes = + static final ArchRule rest_uses_no_service_or_component_stereotypes = noClasses() - .that().resideInAPackage(REST_MODULE_PACKAGE) .should().beAnnotatedWith(Service.class) .orShould().beAnnotatedWith(Component.class) - .because("REST starter beans must be exposed through explicit auto-configuration."); + .because("rest exports Spring beans through explicit configuration."); @ArchTest - static final ArchRule rest_module_uses_no_repository_classes = + static final ArchRule rest_uses_no_repository_classes = noClasses() - .that().resideInAPackage(REST_MODULE_PACKAGE) - .and().areNotInterfaces() + .that().areNotInterfaces() .should().beAnnotatedWith(Repository.class) .because("@Repository is only allowed on Spring Data repository interfaces."); @ArchTest - static final ArchRule bean_methods_are_declared_only_in_config_package = + static final ArchRule bean_methods_are_declared_only_in_config_packages = methods() .that().areAnnotatedWith(Bean.class) - .should().beDeclaredInClassesThat().resideInAPackage(REST_CONFIG_PACKAGE) - .because("REST beans must be exposed through explicit configuration classes."); + .should().beDeclaredInClassesThat().resideInAPackage("..rest.config..") + .because("rest beans must be exposed through explicit configuration classes."); @ArchTest - static final ArchRule configuration_classes_are_declared_only_in_config_package = + static final ArchRule configuration_classes_are_declared_only_in_config_packages = classes() .that().areAnnotatedWith(AutoConfiguration.class) .or().areAnnotatedWith(Configuration.class) - .should().resideInAPackage(REST_CONFIG_PACKAGE) - .because("REST Spring configuration belongs in the config package."); + .should().resideInAPackage("..rest.config..") + .because("Spring configuration belongs in config packages."); @ArchTest - static final ArchRule configuration_properties_follow_rest_conventions = + static final ArchRule configuration_properties_are_declared_only_in_config_packages = classes() .that().areAnnotatedWith(ConfigurationProperties.class) - .should().resideInAPackage(REST_CONFIG_PACKAGE) + .should().resideInAPackage("..rest.config..") .andShould().haveSimpleNameEndingWith("Properties") .andShould().beAnnotatedWith(Validated.class) - .andShould(HAVE_REST_CONFIGURATION_PREFIX) - .because("REST configuration properties must stay validated and under open-daimon.rest."); + .because("rest configuration properties must stay validated in config packages."); @ArchTest - static final ArchRule repositories_are_interfaces = + static final ArchRule rest_controllers_are_declared_only_in_controller_packages = classes() - .that().resideInAPackage(REST_REPOSITORY_PACKAGE) - .and().haveSimpleNameEndingWith("Repository") - .should().beInterfaces() - .because("REST repositories are Spring Data interfaces, not concrete infrastructure classes."); + .that().areAnnotatedWith(RestController.class) + .should().resideInAPackage("..rest.controller..") + .because("HTTP endpoints belong in controller packages."); @ArchTest - static final ArchRule repositories_are_accessed_only_from_service_config_or_repositories = - noClasses() - .that().resideInAPackage(REST_MODULE_PACKAGE) - .and().resideOutsideOfPackages( - REST_CONFIG_PACKAGE, - REST_REPOSITORY_PACKAGE, - REST_SERVICE_PACKAGE) - .should().dependOnClassesThat().resideInAnyPackage( - "io.github.ngirchev.opendaimon.common.repository..", - REST_REPOSITORY_PACKAGE) - .because("repository access must stay behind services and explicit auto-configuration."); + static final ArchRule rest_controller_advice_is_declared_only_in_exception_packages = + classes() + .that().areAnnotatedWith(ControllerAdvice.class) + .or().areAnnotatedWith(RestControllerAdvice.class) + .should().resideInAPackage("..rest.exception..") + .because("REST exception handling belongs in the exception package."); @ArchTest - static final ArchRule controllers_do_not_depend_on_repositories_or_handlers = + static final ArchRule repositories_are_accessed_only_from_service_config_or_repositories = noClasses() - .that().resideInAPackage(REST_CONTROLLER_PACKAGE) - .should().dependOnClassesThat().resideInAnyPackage( - REST_HANDLER_PACKAGE, - REST_REPOSITORY_PACKAGE) - .because("REST controllers should delegate to services instead of handlers or repositories."); + .that().resideOutsideOfPackages( + "..rest.config..", + "..rest.repository..", + "..rest.service..") + .should().dependOnClassesThat().resideInAPackage("..rest.repository..") + .because("repository access must stay behind services and explicit configuration."); @ArchTest - static final ArchRule dto_and_model_are_passive = + static final ArchRule service_layer_does_not_depend_on_http_dtos_or_handlers = noClasses() - .that().resideInAnyPackage( - REST_DTO_PACKAGE, - REST_MODEL_PACKAGE) + .that().resideInAPackage("..rest.service..") .should().dependOnClassesThat().resideInAnyPackage( - REST_CONFIG_PACKAGE, - REST_CONTROLLER_PACKAGE, - REST_HANDLER_PACKAGE, - REST_REPOSITORY_PACKAGE, - REST_SERVICE_PACKAGE) - .because("REST DTO and model classes must not know about runtime layers."); - - @ArchTest - static final ArchRule services_do_not_depend_on_delivery_layers_except_command_bridge = - classes() - .that().resideInAPackage(REST_SERVICE_PACKAGE) - .should(HAVE_NO_REST_DELIVERY_DEPENDENCIES_EXCEPT_COMMAND_BRIDGE) - .because("REST services should stay behind delivery layers; ChatService keeps the current public command bridge."); - - private static boolean isRestDeliveryClass(JavaClass javaClass) { - String packageName = javaClass.getPackageName(); - return packageName.startsWith(REST_CONTROLLER_PACKAGE_PREFIX) - || packageName.startsWith(REST_HANDLER_PACKAGE_PREFIX); - } - - private static boolean isAllowedCommandBridge(JavaClass item, JavaClass targetClass) { - return item.getName().equals(CHAT_SERVICE) - && CHAT_SERVICE_COMMAND_BRIDGE_TYPES.contains(targetClass.getName()); - } + "..rest.dto..", + "..rest.handler..") + .because("REST services expose internal models and must not depend on HTTP DTOs or handlers."); } diff --git a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/controller/SessionControllerContractTest.java b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/controller/SessionControllerContractTest.java index cb416ea7..b13169cd 100644 --- a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/controller/SessionControllerContractTest.java +++ b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/controller/SessionControllerContractTest.java @@ -6,10 +6,10 @@ import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; import io.github.ngirchev.opendaimon.rest.RestTestConfiguration; import io.github.ngirchev.opendaimon.rest.config.AdminSecurityConfig; -import io.github.ngirchev.opendaimon.rest.dto.ChatMessageDto; +import io.github.ngirchev.opendaimon.rest.service.model.ChatMessage; import io.github.ngirchev.opendaimon.rest.dto.ChatRequestDto; -import io.github.ngirchev.opendaimon.rest.dto.ChatResponseDto; -import io.github.ngirchev.opendaimon.rest.dto.ChatSessionDto; +import io.github.ngirchev.opendaimon.rest.service.model.ChatResponse; +import io.github.ngirchev.opendaimon.rest.service.model.ChatSession; import io.github.ngirchev.opendaimon.rest.exception.RestExceptionHandler; import io.github.ngirchev.opendaimon.rest.exception.UnauthorizedException; import io.github.ngirchev.opendaimon.rest.model.RestUser; @@ -101,7 +101,7 @@ class PostNewChat { @DisplayName("returns 200 and JSON with message and sessionId when authorized") void whenAuthorized_returns200AndResponseDto() throws Exception { ChatRequestDto request = new ChatRequestDto("Hello", null, null, TEST_EMAIL); - ChatResponseDto response = new ChatResponseDto<>("AI reply", SESSION_ID); + ChatResponse response = new ChatResponse<>("AI reply", SESSION_ID); when(restAuthorizationService.authorize(eq(TEST_EMAIL), anyString())).thenReturn(restUser); doReturn(response).when(chatService).sendMessageToNewChat(eq("Hello"), eq(restUser), any(), eq(false)); @@ -156,7 +156,7 @@ class PostExistingSession { @DisplayName("returns 200 and JSON with message and sessionId when authorized") void whenAuthorized_returns200AndResponseDto() throws Exception { ChatRequestDto request = new ChatRequestDto("Follow-up", null, null, TEST_EMAIL); - ChatResponseDto response = new ChatResponseDto<>("AI reply", SESSION_ID); + ChatResponse response = new ChatResponse<>("AI reply", SESSION_ID); when(restAuthorizationService.authorize(eq(TEST_EMAIL), anyString())).thenReturn(restUser); doReturn(response).when(chatService).sendMessage(eq(SESSION_ID), eq("Follow-up"), eq(restUser), any(), eq(false)); @@ -190,9 +190,9 @@ class GetSessions { @Test @DisplayName("returns 200 and JSON array of sessions when authorized") void whenAuthorized_returns200AndSessionList() throws Exception { - List sessions = List.of( - new ChatSessionDto("s1", "Chat 1", OffsetDateTime.now()), - new ChatSessionDto("s2", "Chat 2", OffsetDateTime.now()) + List sessions = List.of( + new ChatSession("s1", "Chat 1", OffsetDateTime.now()), + new ChatSession("s2", "Chat 2", OffsetDateTime.now()) ); when(restAuthorizationService.authorize(eq(TEST_EMAIL), anyString())).thenReturn(restUser); when(chatService.getSessions(restUser)).thenReturn(sessions); @@ -222,9 +222,9 @@ class GetSessionMessages { @Test @DisplayName("returns 200 and JSON with sessionId and messages when authorized") void whenAuthorized_returns200AndHistory() throws Exception { - List messages = List.of( - new ChatMessageDto("USER", "Hello"), - new ChatMessageDto("ASSISTANT", "Hi there") + List messages = List.of( + new ChatMessage("USER", "Hello"), + new ChatMessage("ASSISTANT", "Hi there") ); when(restAuthorizationService.authorize(eq(TEST_EMAIL), anyString())).thenReturn(restUser); when(chatService.getChatHistory(SESSION_ID, restUser)).thenReturn(messages); @@ -329,7 +329,7 @@ class PostStreamNewChat { void whenAuthorized_returnsSseStream() throws Exception { ChatRequestDto request = new ChatRequestDto("Hello", null, null, TEST_EMAIL); Flux flux = Flux.just("Hello", " ", "world"); - ChatResponseDto> response = new ChatResponseDto<>(flux, SESSION_ID); + ChatResponse> response = new ChatResponse<>(flux, SESSION_ID); when(restAuthorizationService.authorize(eq(TEST_EMAIL), anyString())).thenReturn(restUser); doReturn(response).when(chatService).sendMessageToNewChat(eq("Hello"), eq(restUser), any(), eq(true)); @@ -376,7 +376,7 @@ class PostStreamExistingSession { void whenAuthorized_returnsSseStream() throws Exception { ChatRequestDto request = new ChatRequestDto("More", null, null, TEST_EMAIL); Flux flux = Flux.just("Response"); - ChatResponseDto> response = new ChatResponseDto<>(flux, SESSION_ID); + ChatResponse> response = new ChatResponse<>(flux, SESSION_ID); when(restAuthorizationService.authorize(eq(TEST_EMAIL), anyString())).thenReturn(restUser); doReturn(response).when(chatService).sendMessage(eq(SESSION_ID), eq("More"), eq(restUser), any(), eq(true)); diff --git a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatHandlerSupportTest.java b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatHandlerSupportTest.java index 464acd46..a3e02583 100644 --- a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatHandlerSupportTest.java +++ b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatHandlerSupportTest.java @@ -8,7 +8,8 @@ import io.github.ngirchev.opendaimon.common.model.ConversationThread; import io.github.ngirchev.opendaimon.common.service.OpenDaimonMessageService; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; -import io.github.ngirchev.opendaimon.rest.dto.ChatRequestDto; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommand; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommandType; import io.github.ngirchev.opendaimon.rest.model.RestUser; import jakarta.servlet.http.HttpServletRequest; import org.junit.jupiter.api.BeforeEach; @@ -57,14 +58,14 @@ class GetRequestLanguage { @Test void whenRequestHasLocale_returnsLanguageCode() { HttpServletRequest request = mockRequestWithLocale(Locale.ENGLISH); - RestChatCommand command = new RestChatCommand(new ChatRequestDto("hi", null, null, null), RestChatCommandType.MESSAGE, request, 1L); + RestChatCommand command = new RestChatCommand("hi", null, null, null, RestChatCommandType.MESSAGE, request, 1L); assertEquals("en", RestChatHandlerSupport.getRequestLanguage(command)); } @Test void whenRequestNull_returnsDefaultLanguage() { - RestChatCommand command = new RestChatCommand(new ChatRequestDto("hi", null, null, null), RestChatCommandType.MESSAGE, null, 1L); + RestChatCommand command = new RestChatCommand("hi", null, null, null, RestChatCommandType.MESSAGE, null, 1L); assertEquals(SupportedLanguages.DEFAULT_LANGUAGE, RestChatHandlerSupport.getRequestLanguage(command)); } @@ -72,7 +73,7 @@ void whenRequestNull_returnsDefaultLanguage() { @Test void whenLocaleNull_returnsDefaultLanguage() { HttpServletRequest request = mockRequestWithLocale(null); - RestChatCommand command = new RestChatCommand(new ChatRequestDto("hi", null, null, null), RestChatCommandType.MESSAGE, request, 1L); + RestChatCommand command = new RestChatCommand("hi", null, null, null, RestChatCommandType.MESSAGE, request, 1L); assertEquals(SupportedLanguages.DEFAULT_LANGUAGE, RestChatHandlerSupport.getRequestLanguage(command)); } @@ -151,7 +152,7 @@ class HandleProcessingError { @Test void whenUserMessageNotNull_savesAssistantErrorMessageAndReturnsRuntimeException() throws Exception { HttpServletRequest request = mockRequestWithLocale(Locale.ENGLISH); - RestChatCommand command = new RestChatCommand(new ChatRequestDto("hi", null, null, null), RestChatCommandType.MESSAGE, request, 1L); + RestChatCommand command = new RestChatCommand("hi", null, null, null, RestChatCommandType.MESSAGE, request, 1L); RestUser user = new RestUser(); AssistantRole role = new AssistantRole(); role.setContent("Role content"); @@ -171,7 +172,7 @@ void whenUserMessageNotNull_savesAssistantErrorMessageAndReturnsRuntimeException @Test void whenUserMessageNull_doesNotCallSaveAssistantErrorMessage() { - RestChatCommand command = new RestChatCommand(new ChatRequestDto("hi", null, null, null), RestChatCommandType.MESSAGE, null, 1L); + RestChatCommand command = new RestChatCommand("hi", null, null, null, RestChatCommandType.MESSAGE, null, 1L); when(messageLocalizationService.getMessage(eq("rest.error.processing"), eq(SupportedLanguages.DEFAULT_LANGUAGE), any())).thenReturn("Error"); RuntimeException result = support.handleProcessingError(command, null, Set.of(), new RuntimeException("x")); @@ -188,7 +189,7 @@ void whenModelCapabilitiesEmpty_usesChatInMetadata() throws Exception { return "{}"; }); when(messageLocalizationService.getMessage(any(), any(), any())).thenReturn("Err"); - RestChatCommand command = new RestChatCommand(new ChatRequestDto("h", null, null, null), RestChatCommandType.MESSAGE, null, 1L); + RestChatCommand command = new RestChatCommand("h", null, null, null, RestChatCommandType.MESSAGE, null, 1L); support.handleProcessingError(command, null, Set.of(), new IllegalStateException("x")); } diff --git a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatMessageCommandHandlerTest.java b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatMessageCommandHandlerTest.java index f358cd85..bcf4fe02 100644 --- a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatMessageCommandHandlerTest.java +++ b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatMessageCommandHandlerTest.java @@ -16,7 +16,8 @@ import io.github.ngirchev.opendaimon.common.service.AIGateway; import io.github.ngirchev.opendaimon.common.service.OpenDaimonMessageService; import io.github.ngirchev.opendaimon.common.service.AIGatewayRegistry; -import io.github.ngirchev.opendaimon.rest.dto.ChatRequestDto; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommand; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommandType; import io.github.ngirchev.opendaimon.rest.model.RestUser; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; import io.github.ngirchev.opendaimon.rest.service.RestMessageService; @@ -109,15 +110,13 @@ class CanHandle { @Test void whenRestChatCommandWithMessageType_returnsTrue() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("hi", null, null, null), RestChatCommandType.MESSAGE, request, 1L); + RestChatCommand command = new RestChatCommand("hi", null, null, null, RestChatCommandType.MESSAGE, request, 1L); assertTrue(handler.canHandle(command)); } @Test void whenRestChatCommandWithStreamType_returnsFalse() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("hi", null, null, null), RestChatCommandType.STREAM, request, 1L); + RestChatCommand command = new RestChatCommand("hi", null, null, null, RestChatCommandType.STREAM, request, 1L); assertFalse(handler.canHandle(command)); } @@ -131,8 +130,7 @@ void whenCommandNotRestChatCommand_returnsFalse() { @Test void whenCommandTypeNull_returnsFalse() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("hi", null, null, null), null, request, 1L); + RestChatCommand command = new RestChatCommand("hi", null, null, null, null, request, 1L); assertFalse(handler.canHandle(command)); } } @@ -153,8 +151,7 @@ class Handle { @Test void whenSuccess_returnsResponseAndSavesAssistantMessage() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("Hello", null, null, "user@test.com"), RestChatCommandType.MESSAGE, request, 1L); + RestChatCommand command = new RestChatCommand("Hello", null, null, "user@test.com", RestChatCommandType.MESSAGE, request, 1L); when(restUserService.findById(1L)).thenReturn(Optional.of(user)); when(restMessageService.saveUserMessage(eq(user), eq("Hello"), eq(RequestType.TEXT), eq(null), eq(request))) .thenReturn(userMessage); @@ -172,8 +169,7 @@ void whenSuccess_returnsResponseAndSavesAssistantMessage() { @Test void whenResponseContentEmpty_savesErrorAndThrowsRuntimeException() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("Hi", null, null, null), RestChatCommandType.MESSAGE, request, 1L); + RestChatCommand command = new RestChatCommand("Hi", null, null, null, RestChatCommandType.MESSAGE, request, 1L); when(restUserService.findById(1L)).thenReturn(Optional.of(user)); when(restMessageService.saveUserMessage(any(), any(), any(), any(), any())).thenReturn(userMessage); when(aiRequestPipeline.prepareCommand(eq(command), any())).thenReturn(aiCommand); @@ -187,8 +183,7 @@ void whenResponseContentEmpty_savesErrorAndThrowsRuntimeException() { @Test void whenUserNotFound_throwsRuntimeException() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("Hi", null, null, null), RestChatCommandType.MESSAGE, request, 99L); + RestChatCommand command = new RestChatCommand("Hi", null, null, null, RestChatCommandType.MESSAGE, request, 99L); when(restUserService.findById(99L)).thenReturn(Optional.empty()); when(support.getMessageLocalizationService()).thenReturn(messageLocalizationService); when(messageLocalizationService.getMessage(eq("rest.user.not.found"), any(), eq(99L))).thenReturn("User not found"); @@ -198,8 +193,7 @@ void whenUserNotFound_throwsRuntimeException() { @Test void whenAccessDeniedException_thrownAsIs() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("Hi", null, null, null), RestChatCommandType.MESSAGE, request, 1L); + RestChatCommand command = new RestChatCommand("Hi", null, null, null, RestChatCommandType.MESSAGE, request, 1L); when(restUserService.findById(1L)).thenReturn(Optional.of(user)); when(restMessageService.saveUserMessage(any(), any(), any(), any(), any())).thenReturn(userMessage); when(aiRequestPipeline.prepareCommand(eq(command), any())).thenReturn(aiCommand); @@ -212,8 +206,7 @@ void whenAccessDeniedException_thrownAsIs() { @Test void whenUserMessageTooLongException_thrownAsIs() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("Hi", null, null, null), RestChatCommandType.MESSAGE, request, 1L); + RestChatCommand command = new RestChatCommand("Hi", null, null, null, RestChatCommandType.MESSAGE, request, 1L); when(restUserService.findById(1L)).thenReturn(Optional.of(user)); when(restMessageService.saveUserMessage(any(), any(), any(), any(), any())).thenThrow(new UserMessageTooLongException("too long")); @@ -223,8 +216,7 @@ void whenUserMessageTooLongException_thrownAsIs() { @Test void whenGenericException_callsSupportHandleProcessingErrorAndRethrows() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("Hi", null, null, null), RestChatCommandType.MESSAGE, request, 1L); + RestChatCommand command = new RestChatCommand("Hi", null, null, null, RestChatCommandType.MESSAGE, request, 1L); when(restUserService.findById(1L)).thenReturn(Optional.of(user)); when(restMessageService.saveUserMessage(any(), any(), any(), any(), any())).thenReturn(userMessage); when(aiRequestPipeline.prepareCommand(eq(command), any())).thenReturn(aiCommand); diff --git a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatStreamMessageCommandHandlerTest.java b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatStreamMessageCommandHandlerTest.java index 10e853c2..5417b208 100644 --- a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatStreamMessageCommandHandlerTest.java +++ b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/handler/RestChatStreamMessageCommandHandlerTest.java @@ -17,7 +17,8 @@ import io.github.ngirchev.opendaimon.common.service.OpenDaimonMessageService; import io.github.ngirchev.opendaimon.common.service.AIGatewayRegistry; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; -import io.github.ngirchev.opendaimon.rest.dto.ChatRequestDto; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommand; +import io.github.ngirchev.opendaimon.rest.command.RestChatCommandType; import io.github.ngirchev.opendaimon.rest.model.RestUser; import io.github.ngirchev.opendaimon.rest.service.RestMessageService; import io.github.ngirchev.opendaimon.rest.service.RestUserService; @@ -109,15 +110,13 @@ class CanHandle { @Test void whenRestChatCommandWithStreamType_returnsTrue() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("hi", null, null, null), RestChatCommandType.STREAM, request, 1L); + RestChatCommand command = new RestChatCommand("hi", null, null, null, RestChatCommandType.STREAM, request, 1L); assertTrue(handler.canHandle(command)); } @Test void whenRestChatCommandWithMessageType_returnsFalse() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("hi", null, null, null), RestChatCommandType.MESSAGE, request, 1L); + RestChatCommand command = new RestChatCommand("hi", null, null, null, RestChatCommandType.MESSAGE, request, 1L); assertFalse(handler.canHandle(command)); } @@ -131,8 +130,7 @@ void whenCommandNotRestChatCommand_returnsFalse() { @Test void whenCommandTypeNull_returnsFalse() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("hi", null, null, null), null, request, 1L); + RestChatCommand command = new RestChatCommand("hi", null, null, null, null, request, 1L); assertFalse(handler.canHandle(command)); } } @@ -153,8 +151,7 @@ class Handle { @Test void whenSuccess_returnsFluxAndSavesAssistantMessageOnComplete() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("Hello", null, null, "user@test.com"), RestChatCommandType.STREAM, request, 1L); + RestChatCommand command = new RestChatCommand("Hello", null, null, "user@test.com", RestChatCommandType.STREAM, request, 1L); when(restUserService.findById(1L)).thenReturn(Optional.of(user)); when(restMessageService.saveUserMessage(eq(user), eq("Hello"), eq(RequestType.TEXT), eq(null), eq(request))) .thenReturn(userMessage); @@ -177,8 +174,7 @@ void whenSuccess_returnsFluxAndSavesAssistantMessageOnComplete() { @Test void whenResponseNotSpringAIStream_handleProcessingErrorReturnsIllegalStateAndRethrows() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("Hi", null, null, null), RestChatCommandType.STREAM, request, 1L); + RestChatCommand command = new RestChatCommand("Hi", null, null, null, RestChatCommandType.STREAM, request, 1L); when(restUserService.findById(1L)).thenReturn(Optional.of(user)); when(restMessageService.saveUserMessage(any(), any(), any(), any(), any())).thenReturn(userMessage); when(aiRequestPipeline.prepareCommand(eq(command), any())).thenReturn(aiCommand); @@ -195,8 +191,7 @@ void whenResponseNotSpringAIStream_handleProcessingErrorReturnsIllegalStateAndRe @Test void whenUserNotFound_throwsRuntimeException() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("Hi", null, null, null), RestChatCommandType.STREAM, request, 99L); + RestChatCommand command = new RestChatCommand("Hi", null, null, null, RestChatCommandType.STREAM, request, 99L); when(restUserService.findById(99L)).thenReturn(Optional.empty()); when(support.getMessageLocalizationService()).thenReturn(messageLocalizationService); when(messageLocalizationService.getMessage(eq("rest.user.not.found"), any(), eq(99L))).thenReturn("User not found"); @@ -206,8 +201,7 @@ void whenUserNotFound_throwsRuntimeException() { @Test void whenAccessDeniedException_thrownAsIs() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("Hi", null, null, null), RestChatCommandType.STREAM, request, 1L); + RestChatCommand command = new RestChatCommand("Hi", null, null, null, RestChatCommandType.STREAM, request, 1L); when(restUserService.findById(1L)).thenReturn(Optional.of(user)); when(restMessageService.saveUserMessage(any(), any(), any(), any(), any())).thenReturn(userMessage); when(aiRequestPipeline.prepareCommand(eq(command), any())).thenReturn(aiCommand); @@ -220,8 +214,7 @@ void whenAccessDeniedException_thrownAsIs() { @Test void whenUserMessageTooLongException_thrownAsIs() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("Hi", null, null, null), RestChatCommandType.STREAM, request, 1L); + RestChatCommand command = new RestChatCommand("Hi", null, null, null, RestChatCommandType.STREAM, request, 1L); when(restUserService.findById(1L)).thenReturn(Optional.of(user)); when(restMessageService.saveUserMessage(any(), any(), any(), any(), any())).thenThrow(new UserMessageTooLongException("too long")); @@ -231,8 +224,7 @@ void whenUserMessageTooLongException_thrownAsIs() { @Test void whenGenericException_callsSupportHandleProcessingErrorAndRethrows() { - RestChatCommand command = new RestChatCommand( - new ChatRequestDto("Hi", null, null, null), RestChatCommandType.STREAM, request, 1L); + RestChatCommand command = new RestChatCommand("Hi", null, null, null, RestChatCommandType.STREAM, request, 1L); when(restUserService.findById(1L)).thenReturn(Optional.of(user)); when(restMessageService.saveUserMessage(any(), any(), any(), any(), any())).thenReturn(userMessage); when(aiRequestPipeline.prepareCommand(eq(command), any())).thenReturn(aiCommand); diff --git a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/service/AdminQueryServiceTest.java b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/service/AdminQueryServiceTest.java index 99c8c107..397179b4 100644 --- a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/service/AdminQueryServiceTest.java +++ b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/service/AdminQueryServiceTest.java @@ -7,10 +7,10 @@ import io.github.ngirchev.opendaimon.common.model.ResponseStatus; import io.github.ngirchev.opendaimon.common.model.ThreadScopeKind; import io.github.ngirchev.opendaimon.common.repository.OpenDaimonMessageRepository; -import io.github.ngirchev.opendaimon.rest.dto.admin.ConversationSummaryDto; -import io.github.ngirchev.opendaimon.rest.dto.admin.MessageDetailDto; -import io.github.ngirchev.opendaimon.rest.dto.admin.MessageSummaryDto; -import io.github.ngirchev.opendaimon.rest.dto.admin.PageResponseDto; +import io.github.ngirchev.opendaimon.rest.service.model.AdminConversationSummary; +import io.github.ngirchev.opendaimon.rest.service.model.AdminMessageDetail; +import io.github.ngirchev.opendaimon.rest.service.model.AdminMessageSummary; +import io.github.ngirchev.opendaimon.rest.service.model.AdminPageResponse; import io.github.ngirchev.opendaimon.rest.exception.UnauthorizedException; import io.github.ngirchev.opendaimon.rest.model.RestUser; import io.github.ngirchev.opendaimon.rest.repository.AdminConversationRepository; @@ -64,10 +64,10 @@ void shouldMapConversationSummaryWithRestUser() { Page page = new PageImpl<>(List.of(t), pageable, 1); when(adminConversationRepository.findAllWithFilters(any(), any(), any(), eq(pageable))).thenReturn(page); - PageResponseDto result = service.listConversations(null, null, null, pageable); + AdminPageResponse result = service.listConversations(null, null, null, pageable); assertThat(result.content()).hasSize(1); - ConversationSummaryDto dto = result.content().get(0); + AdminConversationSummary dto = result.content().get(0); assertThat(dto.id()).isEqualTo(10L); assertThat(dto.threadKey()).isEqualTo("key-10"); assertThat(dto.scopeKind()).isEqualTo(ThreadScopeKind.USER.name()); @@ -97,7 +97,7 @@ void shouldReturnMessagesOrderedByRepository() { when(adminConversationRepository.findByIdWithUser(10L)).thenReturn(Optional.of(t)); when(messageRepository.findByThreadOrderBySequenceNumberAsc(t)).thenReturn(List.of(m1, m2)); - List result = service.listMessages(10L); + List result = service.listMessages(10L); assertThat(result).hasSize(2); assertThat(result.get(0).role()).isEqualTo("USER"); @@ -116,7 +116,7 @@ void shouldTruncateContentPreview() { when(adminConversationRepository.findByIdWithUser(10L)).thenReturn(Optional.of(t)); when(messageRepository.findByThreadOrderBySequenceNumberAsc(t)).thenReturn(List.of(m)); - List result = service.listMessages(10L); + List result = service.listMessages(10L); assertThat(result).hasSize(1); assertThat(result.get(0).contentPreview()).hasSize(201); @@ -141,7 +141,7 @@ void shouldMapMessageDetailAttachments() { m.setMetadata(Map.of("client_ip", "127.0.0.1")); when(messageRepository.findById(5L)).thenReturn(Optional.of(m)); - MessageDetailDto dto = service.getMessage(5L); + AdminMessageDetail dto = service.getMessage(5L); assertThat(dto.id()).isEqualTo(5L); assertThat(dto.threadId()).isEqualTo(10L); diff --git a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/service/ChatServiceTest.java b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/service/ChatServiceTest.java index 91f462d8..196e8e49 100644 --- a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/service/ChatServiceTest.java +++ b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/service/ChatServiceTest.java @@ -9,9 +9,9 @@ import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; import io.github.ngirchev.opendaimon.common.service.CommandSyncService; import io.github.ngirchev.opendaimon.common.service.ConversationThreadService; -import io.github.ngirchev.opendaimon.rest.dto.ChatMessageDto; -import io.github.ngirchev.opendaimon.rest.dto.ChatResponseDto; -import io.github.ngirchev.opendaimon.rest.dto.ChatSessionDto; +import io.github.ngirchev.opendaimon.rest.service.model.ChatMessage; +import io.github.ngirchev.opendaimon.rest.service.model.ChatResponse; +import io.github.ngirchev.opendaimon.rest.service.model.ChatSession; import io.github.ngirchev.opendaimon.rest.exception.UnauthorizedException; import io.github.ngirchev.opendaimon.rest.model.RestUser; import jakarta.servlet.http.HttpServletRequest; @@ -82,7 +82,7 @@ void whenNoActiveThread_createsNewThreadAndSendsMessage() { when(conversationThreadService.createNewThread(currentUser)).thenReturn(thread); when(commandSyncService.syncAndHandle(any(), any())).thenReturn("AI response"); - ChatResponseDto result = service.sendMessageToNewChat("Hello", currentUser, request, false); + ChatResponse result = service.sendMessageToNewChat("Hello", currentUser, request, false); assertEquals("AI response", result.message()); assertEquals("session-123", result.sessionId()); @@ -98,7 +98,7 @@ void whenActiveThreadExists_closesItThenCreatesNewAndSends() { when(conversationThreadService.createNewThread(currentUser)).thenReturn(thread); when(commandSyncService.syncAndHandle(any(), any())).thenReturn("OK"); - ChatResponseDto result = service.sendMessageToNewChat("Hi", currentUser, request, false); + ChatResponse result = service.sendMessageToNewChat("Hi", currentUser, request, false); assertEquals("OK", result.message()); verify(conversationThreadService).closeThread(activeThread); @@ -115,7 +115,7 @@ void whenSessionBelongsToUser_activatesThreadAndSends() { when(threadRepository.findByThreadKey("session-123")).thenReturn(Optional.of(thread)); when(commandSyncService.syncAndHandle(any(), any())).thenReturn("Reply"); - ChatResponseDto result = service.sendMessage("session-123", "Hi", currentUser, request, false); + ChatResponse result = service.sendMessage("session-123", "Hi", currentUser, request, false); assertEquals("Reply", result.message()); assertEquals("session-123", result.sessionId()); @@ -153,7 +153,7 @@ void mapsThreadsToChatSessionDtos() { thread.setTitle(null); when(threadRepository.findByUserOrderByLastActivityAtDesc(currentUser)).thenReturn(List.of(thread)); - List result = service.getSessions(currentUser); + List result = service.getSessions(currentUser); assertEquals(1, result.size()); assertEquals("session-123", result.get(0).sessionId()); @@ -165,7 +165,7 @@ void mapsThreadsToChatSessionDtos() { void whenThreadHasTitle_usesIt() { when(threadRepository.findByUserOrderByLastActivityAtDesc(currentUser)).thenReturn(List.of(thread)); - List result = service.getSessions(currentUser); + List result = service.getSessions(currentUser); assertEquals("Test", result.get(0).name()); } @@ -190,7 +190,7 @@ void whenSessionBelongsToUser_returnsMessagesExcludingSystem() { when(messageRepository.findByThreadOrderBySequenceNumberAsc(thread)) .thenReturn(List.of(systemMsg, userMsg, assistantMsg)); - List result = service.getChatHistory("session-123", currentUser); + List result = service.getChatHistory("session-123", currentUser); assertEquals(2, result.size()); assertEquals("USER", result.get(0).role()); diff --git a/opendaimon-spring-ai/pom.xml b/opendaimon-spring-ai/pom.xml index 1fc9a87f..1206e80c 100644 --- a/opendaimon-spring-ai/pom.xml +++ b/opendaimon-spring-ai/pom.xml @@ -264,6 +264,24 @@ junit-jupiter-api test + + com.tngtech.archunit + archunit + ${archunit.version} + test + + + com.tngtech.archunit + archunit-junit5-api + ${archunit.version} + test + + + com.tngtech.archunit + archunit-junit5-engine + ${archunit.version} + test + org.mockito mockito-core @@ -298,6 +316,9 @@ maven-dependency-plugin + + com.tngtech.archunit:archunit-junit5-engine + com.tngtech.archunit:archunit-junit5-engine + + + org.apache.maven.plugins maven-enforcer-plugin diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/TelegramSupportedCommandProvider.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/TelegramSupportedCommandProvider.java similarity index 87% rename from opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/TelegramSupportedCommandProvider.java rename to opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/TelegramSupportedCommandProvider.java index eff108b5..bb89d5a5 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/TelegramSupportedCommandProvider.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/TelegramSupportedCommandProvider.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler; +package io.github.ngirchev.opendaimon.telegram.command; /** * Marker interface for handlers that can provide the description of their supported command @@ -12,5 +12,3 @@ public interface TelegramSupportedCommandProvider { */ String getSupportedCommandText(String languageCode); } - - diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/AbstractTelegramCommandHandler.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/AbstractTelegramCommandHandler.java index 7ff8dec1..1883db41 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/AbstractTelegramCommandHandler.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/AbstractTelegramCommandHandler.java @@ -12,6 +12,7 @@ import io.github.ngirchev.opendaimon.telegram.TelegramBot; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; +import io.github.ngirchev.opendaimon.telegram.command.TelegramSupportedCommandProvider; import io.github.ngirchev.opendaimon.telegram.service.TypingIndicatorService; @Slf4j diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/AbstractTelegramCommandHandlerWithResponseSend.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/AbstractTelegramCommandHandlerWithResponseSend.java index 91ba9b9b..d95bc3ea 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/AbstractTelegramCommandHandlerWithResponseSend.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/AbstractTelegramCommandHandlerWithResponseSend.java @@ -14,6 +14,7 @@ import io.github.ngirchev.opendaimon.telegram.TelegramBot; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; +import io.github.ngirchev.opendaimon.telegram.command.TelegramSupportedCommandProvider; import io.github.ngirchev.opendaimon.telegram.service.TypingIndicatorService; @Slf4j diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/BackoffCommandHandler.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/BackoffCommandHandler.java index a1899a06..4f507c08 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/BackoffCommandHandler.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/BackoffCommandHandler.java @@ -8,7 +8,7 @@ import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; import io.github.ngirchev.opendaimon.telegram.command.handler.AbstractTelegramCommandHandlerWithResponseSend; -import io.github.ngirchev.opendaimon.telegram.command.handler.TelegramSupportedCommandProvider; +import io.github.ngirchev.opendaimon.telegram.command.TelegramSupportedCommandProvider; import io.github.ngirchev.opendaimon.telegram.service.TypingIndicatorService; import java.util.Objects; diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/MessageTelegramCommandHandler.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/MessageTelegramCommandHandler.java index 68c49dcf..3c7a2fe9 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/MessageTelegramCommandHandler.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/MessageTelegramCommandHandler.java @@ -19,10 +19,10 @@ import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; import io.github.ngirchev.opendaimon.telegram.command.handler.AbstractTelegramCommandHandler; import io.github.ngirchev.opendaimon.telegram.command.handler.AbstractTelegramCommandHandlerWithResponseSend; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerContext; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerErrorType; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerEvent; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerState; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerContext; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerErrorType; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerEvent; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerState; import io.github.ngirchev.opendaimon.telegram.config.TelegramProperties; import io.github.ngirchev.opendaimon.telegram.model.TelegramUser; import io.github.ngirchev.opendaimon.telegram.service.PersistentKeyboardService; diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/StartTelegramCommandHandler.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/StartTelegramCommandHandler.java index 81621397..3e951d6f 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/StartTelegramCommandHandler.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/StartTelegramCommandHandler.java @@ -7,7 +7,7 @@ import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; import io.github.ngirchev.opendaimon.telegram.command.handler.AbstractTelegramCommandHandlerWithResponseSend; -import io.github.ngirchev.opendaimon.telegram.command.handler.TelegramSupportedCommandProvider; +import io.github.ngirchev.opendaimon.telegram.command.TelegramSupportedCommandProvider; import io.github.ngirchev.opendaimon.telegram.service.TypingIndicatorService; import java.util.Objects; diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/config/TelegramCommandHandlerConfig.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/config/TelegramCommandHandlerConfig.java index fea2009f..88a39310 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/config/TelegramCommandHandlerConfig.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/config/TelegramCommandHandlerConfig.java @@ -17,15 +17,15 @@ import io.github.ngirchev.opendaimon.common.repository.OpenDaimonMessageRepository; import io.github.ngirchev.opendaimon.common.service.*; import io.github.ngirchev.opendaimon.telegram.TelegramBot; -import io.github.ngirchev.opendaimon.telegram.command.handler.TelegramSupportedCommandProvider; +import io.github.ngirchev.opendaimon.telegram.command.TelegramSupportedCommandProvider; import io.github.ngirchev.opendaimon.telegram.command.handler.impl.*; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerActions; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerContext; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerEvent; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerFsmFactory; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerState; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageHandlerActions; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageSender; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerActions; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerContext; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerEvent; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerFsmFactory; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerState; +import io.github.ngirchev.opendaimon.telegram.service.fsm.TelegramMessageHandlerActions; +import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageSender; import io.github.ngirchev.opendaimon.telegram.service.ChatSettingsService; import io.github.ngirchev.opendaimon.telegram.service.InMemoryModelSelectionSession; import io.github.ngirchev.opendaimon.telegram.service.ModelSelectionSession; diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/config/TelegramServiceConfig.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/config/TelegramServiceConfig.java index 9c306a54..20cfc3c8 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/config/TelegramServiceConfig.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/config/TelegramServiceConfig.java @@ -25,7 +25,7 @@ import io.github.ngirchev.opendaimon.common.storage.config.StorageProperties; import io.github.ngirchev.opendaimon.common.storage.service.FileStorageService; import io.github.ngirchev.opendaimon.telegram.TelegramBot; -import io.github.ngirchev.opendaimon.telegram.command.handler.TelegramSupportedCommandProvider; +import io.github.ngirchev.opendaimon.telegram.command.TelegramSupportedCommandProvider; import io.github.ngirchev.opendaimon.telegram.repository.TelegramGroupRepository; import io.github.ngirchev.opendaimon.telegram.repository.TelegramUserRepository; import io.github.ngirchev.opendaimon.telegram.repository.TelegramUserSessionRepository; diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamRenderer.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamRenderer.java index 97ccac9f..4ee8d1c7 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamRenderer.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamRenderer.java @@ -5,7 +5,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.github.ngirchev.opendaimon.common.agent.AgentStreamEvent; import io.github.ngirchev.opendaimon.common.model.ThinkingMode; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerContext; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerContext; import io.github.ngirchev.opendaimon.telegram.model.TelegramUser; import lombok.RequiredArgsConstructor; diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamView.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamView.java index 3e1f9b68..a34bbba6 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamView.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamView.java @@ -1,7 +1,7 @@ package io.github.ngirchev.opendaimon.telegram.service; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerContext; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageSender; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerContext; +import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageSender; import io.github.ngirchev.opendaimon.telegram.config.TelegramProperties; import io.github.ngirchev.opendaimon.common.service.AIUtils; import lombok.extern.slf4j.Slf4j; diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramBotMenuService.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramBotMenuService.java index f963b023..272a1da0 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramBotMenuService.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramBotMenuService.java @@ -7,7 +7,7 @@ import org.telegram.telegrambots.meta.exceptions.TelegramApiException; import io.github.ngirchev.opendaimon.common.model.User; import io.github.ngirchev.opendaimon.telegram.TelegramBot; -import io.github.ngirchev.opendaimon.telegram.command.handler.TelegramSupportedCommandProvider; +import io.github.ngirchev.opendaimon.telegram.command.TelegramSupportedCommandProvider; import io.github.ngirchev.opendaimon.telegram.model.TelegramGroup; import io.github.ngirchev.opendaimon.telegram.model.TelegramUser; diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramDeliveryFailedException.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramDeliveryFailedException.java similarity index 79% rename from opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramDeliveryFailedException.java rename to opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramDeliveryFailedException.java index ef1ed435..87ad71b6 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramDeliveryFailedException.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramDeliveryFailedException.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm; +package io.github.ngirchev.opendaimon.telegram.service; public class TelegramDeliveryFailedException extends RuntimeException { diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramMessageSender.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramMessageSender.java similarity index 99% rename from opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramMessageSender.java rename to opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramMessageSender.java index efbd9f3b..ec9251c5 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramMessageSender.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramMessageSender.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm; +package io.github.ngirchev.opendaimon.telegram.service; import io.github.ngirchev.opendaimon.common.model.ConversationThread; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerActions.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerActions.java similarity index 97% rename from opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerActions.java rename to opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerActions.java index a3072ca1..bb42368b 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerActions.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerActions.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm; +package io.github.ngirchev.opendaimon.telegram.service.fsm; /** * Actions invoked by the message handler FSM during state transitions. diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerContext.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerContext.java similarity index 99% rename from opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerContext.java rename to opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerContext.java index 0c901a5e..159c2873 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerContext.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerContext.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm; +package io.github.ngirchev.opendaimon.telegram.service.fsm; import io.github.ngirchev.fsm.StateContext; import io.github.ngirchev.fsm.Transition; diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerErrorType.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerErrorType.java similarity index 92% rename from opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerErrorType.java rename to opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerErrorType.java index a5bcb0b6..30877f5c 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerErrorType.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerErrorType.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm; +package io.github.ngirchev.opendaimon.telegram.service.fsm; /** * Error types for the message handler FSM. diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerEvent.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerEvent.java similarity index 80% rename from opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerEvent.java rename to opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerEvent.java index 8f28b3c3..d312dc92 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerEvent.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerEvent.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm; +package io.github.ngirchev.opendaimon.telegram.service.fsm; /** * Events that drive the message handler FSM. diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerFsmFactory.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerFsmFactory.java similarity index 94% rename from opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerFsmFactory.java rename to opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerFsmFactory.java index 23dd3d89..8629a80c 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerFsmFactory.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerFsmFactory.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm; +package io.github.ngirchev.opendaimon.telegram.service.fsm; import io.github.ngirchev.fsm.Action; import io.github.ngirchev.fsm.FsmFactory; @@ -9,8 +9,8 @@ import java.util.function.Consumer; import java.util.function.Predicate; -import static io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerEvent.HANDLE; -import static io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerState.*; +import static io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerEvent.HANDLE; +import static io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerState.*; /** * Creates the message handler FSM with all transitions defined declaratively. diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerState.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerState.java similarity index 96% rename from opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerState.java rename to opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerState.java index d31390ff..07e4d70e 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerState.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerState.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm; +package io.github.ngirchev.opendaimon.telegram.service.fsm; /** * States for the Telegram message handler FSM. diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramMessageHandlerActions.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/TelegramMessageHandlerActions.java similarity index 99% rename from opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramMessageHandlerActions.java rename to opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/TelegramMessageHandlerActions.java index 15bc8e5c..ac48a099 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramMessageHandlerActions.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/fsm/TelegramMessageHandlerActions.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm; +package io.github.ngirchev.opendaimon.telegram.service.fsm; import io.github.ngirchev.opendaimon.common.agent.AgentExecutor; import io.github.ngirchev.opendaimon.common.agent.AgentStrategy; @@ -36,7 +36,9 @@ import io.github.ngirchev.opendaimon.telegram.service.ReplyImageAttachmentService; import io.github.ngirchev.opendaimon.telegram.service.TelegramAgentStreamModel; import io.github.ngirchev.opendaimon.telegram.service.TelegramAgentStreamView; +import io.github.ngirchev.opendaimon.telegram.service.TelegramDeliveryFailedException; import io.github.ngirchev.opendaimon.telegram.service.TelegramHtmlEscaper; +import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageSender; import io.github.ngirchev.opendaimon.telegram.service.TelegramProgressBatcher; import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageService; import io.github.ngirchev.opendaimon.telegram.service.TelegramUserService; diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/arch/TelegramArchitectureTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/arch/TelegramArchitectureTest.java new file mode 100644 index 00000000..e5afc831 --- /dev/null +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/arch/TelegramArchitectureTest.java @@ -0,0 +1,83 @@ +package io.github.ngirchev.opendaimon.telegram.arch; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.classes; +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.methods; +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; + +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.junit.AnalyzeClasses; +import com.tngtech.archunit.junit.ArchTest; +import com.tngtech.archunit.lang.ArchRule; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Repository; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +@AnalyzeClasses( + packages = "io.github.ngirchev.opendaimon.telegram", + importOptions = { + ImportOption.DoNotIncludeTests.class, + ImportOption.DoNotIncludeJars.class + } +) +class TelegramArchitectureTest { + + @ArchTest + static final ArchRule telegram_uses_no_service_or_component_stereotypes = + noClasses() + .should().beAnnotatedWith(Service.class) + .orShould().beAnnotatedWith(Component.class) + .because("telegram exports Spring beans through explicit configuration."); + + @ArchTest + static final ArchRule telegram_uses_no_repository_classes = + noClasses() + .that().areNotInterfaces() + .should().beAnnotatedWith(Repository.class) + .because("@Repository is only allowed on Spring Data repository interfaces."); + + @ArchTest + static final ArchRule bean_methods_are_declared_only_in_config_packages = + methods() + .that().areAnnotatedWith(Bean.class) + .should().beDeclaredInClassesThat().resideInAPackage("..telegram.config..") + .because("telegram beans must be exposed through explicit configuration classes."); + + @ArchTest + static final ArchRule configuration_classes_are_declared_only_in_config_packages = + classes() + .that().areAnnotatedWith(AutoConfiguration.class) + .or().areAnnotatedWith(Configuration.class) + .should().resideInAPackage("..telegram.config..") + .because("Spring configuration belongs in config packages."); + + @ArchTest + static final ArchRule configuration_properties_are_declared_only_in_config_packages = + classes() + .that().areAnnotatedWith(ConfigurationProperties.class) + .should().resideInAPackage("..telegram.config..") + .andShould().haveSimpleNameEndingWith("Properties") + .andShould().beAnnotatedWith(Validated.class) + .because("telegram configuration properties must stay validated in config packages."); + + @ArchTest + static final ArchRule repositories_are_accessed_only_from_service_config_or_repositories = + noClasses() + .that().resideOutsideOfPackages( + "..telegram.config..", + "..telegram.repository..", + "..telegram.service..") + .should().dependOnClassesThat().resideInAPackage("..telegram.repository..") + .because("repository access must stay behind services and explicit configuration."); + + @ArchTest + static final ArchRule service_layer_does_not_depend_on_handler_implementations = + noClasses() + .that().resideInAPackage("..telegram.service..") + .should().dependOnClassesThat().resideInAPackage("..telegram.command.handler..") + .because("telegram services may depend on command inputs, not handler implementation details."); +} diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/StartTelegramTextCommandHandlerProviderTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/StartTelegramTextCommandHandlerProviderTest.java index 486021f8..cae1505e 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/StartTelegramTextCommandHandlerProviderTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/StartTelegramTextCommandHandlerProviderTest.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler; +package io.github.ngirchev.opendaimon.telegram.command; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/BackoffCommandHandlerTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/BackoffCommandHandlerTest.java index f63f6975..975c57ff 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/BackoffCommandHandlerTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/BackoffCommandHandlerTest.java @@ -5,7 +5,7 @@ import io.github.ngirchev.opendaimon.telegram.TelegramBot; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; -import io.github.ngirchev.opendaimon.telegram.command.handler.TelegramSupportedCommandProvider; +import io.github.ngirchev.opendaimon.telegram.command.TelegramSupportedCommandProvider; import io.github.ngirchev.opendaimon.telegram.service.TypingIndicatorService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/MessageTelegramCommandHandlerTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/MessageTelegramCommandHandlerTest.java index 46ab93e8..43aed161 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/MessageTelegramCommandHandlerTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/MessageTelegramCommandHandlerTest.java @@ -18,12 +18,12 @@ import io.github.ngirchev.opendaimon.common.service.AIGatewayRegistry; import io.github.ngirchev.opendaimon.common.service.OpenDaimonMessageService; import io.github.ngirchev.opendaimon.common.service.MessageLocalizationService; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerContext; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerEvent; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerFsmFactory; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerState; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageHandlerActions; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageSender; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerContext; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerEvent; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerFsmFactory; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerState; +import io.github.ngirchev.opendaimon.telegram.service.fsm.TelegramMessageHandlerActions; +import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageSender; import io.github.ngirchev.opendaimon.telegram.service.TelegramAgentStreamView; import io.github.ngirchev.opendaimon.telegram.service.TelegramChatPacer; import org.junit.jupiter.api.BeforeEach; diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/StartTelegramCommandHandlerTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/StartTelegramCommandHandlerTest.java index 0eeb4a5d..7a7ebf15 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/StartTelegramCommandHandlerTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/StartTelegramCommandHandlerTest.java @@ -5,7 +5,7 @@ import io.github.ngirchev.opendaimon.telegram.TelegramBot; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; -import io.github.ngirchev.opendaimon.telegram.command.handler.TelegramSupportedCommandProvider; +import io.github.ngirchev.opendaimon.telegram.command.TelegramSupportedCommandProvider; import io.github.ngirchev.opendaimon.telegram.service.TypingIndicatorService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamRendererTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamRendererTest.java index 77a23add..37248637 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamRendererTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamRendererTest.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.github.ngirchev.opendaimon.common.agent.AgentStreamEvent; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerContext; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerContext; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.telegram.telegrambots.meta.api.objects.Message; diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamViewConcurrencyTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamViewConcurrencyTest.java index 30607ae9..5efea838 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamViewConcurrencyTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamViewConcurrencyTest.java @@ -2,8 +2,8 @@ import io.github.ngirchev.opendaimon.common.agent.AgentStreamEvent; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerContext; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageSender; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerContext; +import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageSender; import io.github.ngirchev.opendaimon.telegram.config.TelegramProperties; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamViewTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamViewTest.java index a4b99d15..c9567194 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamViewTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamViewTest.java @@ -2,8 +2,8 @@ import io.github.ngirchev.opendaimon.common.agent.AgentStreamEvent; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.MessageHandlerContext; -import io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm.TelegramMessageSender; +import io.github.ngirchev.opendaimon.telegram.service.fsm.MessageHandlerContext; +import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageSender; import io.github.ngirchev.opendaimon.telegram.config.TelegramProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramBotMenuServiceTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramBotMenuServiceTest.java index 53b18e39..6464fa34 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramBotMenuServiceTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramBotMenuServiceTest.java @@ -1,7 +1,7 @@ package io.github.ngirchev.opendaimon.telegram.service; import io.github.ngirchev.opendaimon.telegram.TelegramBot; -import io.github.ngirchev.opendaimon.telegram.command.handler.TelegramSupportedCommandProvider; +import io.github.ngirchev.opendaimon.telegram.command.TelegramSupportedCommandProvider; import io.github.ngirchev.opendaimon.telegram.model.TelegramUser; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerContextTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerContextTest.java similarity index 96% rename from opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerContextTest.java rename to opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerContextTest.java index c1abff0d..99d0a2f3 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/MessageHandlerContextTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/fsm/MessageHandlerContextTest.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm; +package io.github.ngirchev.opendaimon.telegram.service.fsm; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; import org.junit.jupiter.api.DisplayName; diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramMessageHandlerActionsAgentTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/fsm/TelegramMessageHandlerActionsAgentTest.java similarity index 99% rename from opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramMessageHandlerActionsAgentTest.java rename to opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/fsm/TelegramMessageHandlerActionsAgentTest.java index 0e05c768..fc32743c 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramMessageHandlerActionsAgentTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/fsm/TelegramMessageHandlerActionsAgentTest.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm; +package io.github.ngirchev.opendaimon.telegram.service.fsm; import com.fasterxml.jackson.databind.ObjectMapper; import io.github.ngirchev.opendaimon.common.agent.AgentExecutor; @@ -21,6 +21,7 @@ import io.github.ngirchev.opendaimon.telegram.service.TelegramAgentStreamRenderer; import io.github.ngirchev.opendaimon.telegram.service.TelegramAgentStreamView; import io.github.ngirchev.opendaimon.telegram.service.TelegramChatPacer; +import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageSender; import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageService; import io.github.ngirchev.opendaimon.telegram.service.TelegramUserService; import io.github.ngirchev.opendaimon.telegram.service.TelegramUserSessionService; diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramMessageHandlerActionsStreamingTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/fsm/TelegramMessageHandlerActionsStreamingTest.java similarity index 99% rename from opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramMessageHandlerActionsStreamingTest.java rename to opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/fsm/TelegramMessageHandlerActionsStreamingTest.java index a5be84b6..643b4027 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/command/handler/impl/fsm/TelegramMessageHandlerActionsStreamingTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/fsm/TelegramMessageHandlerActionsStreamingTest.java @@ -1,4 +1,4 @@ -package io.github.ngirchev.opendaimon.telegram.command.handler.impl.fsm; +package io.github.ngirchev.opendaimon.telegram.service.fsm; import com.fasterxml.jackson.databind.ObjectMapper; import io.github.ngirchev.opendaimon.common.agent.AgentExecutor; @@ -17,6 +17,7 @@ import io.github.ngirchev.opendaimon.telegram.service.TelegramAgentStreamRenderer; import io.github.ngirchev.opendaimon.telegram.service.TelegramAgentStreamView; import io.github.ngirchev.opendaimon.telegram.service.TelegramChatPacer; +import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageSender; import io.github.ngirchev.opendaimon.telegram.service.TelegramMessageService; import io.github.ngirchev.opendaimon.telegram.model.TelegramUser; import io.github.ngirchev.opendaimon.telegram.service.TelegramUserService; diff --git a/pom.xml b/pom.xml index 0be764d6..905f65a0 100644 --- a/pom.xml +++ b/pom.xml @@ -33,8 +33,8 @@ - MIT License - https://opensource.org/licenses/MIT + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt From ba33a1c6ba0fcc0720a09c462c98d4e0449550a6 Mon Sep 17 00:00:00 2001 From: ngirchev Date: Fri, 1 May 2026 17:21:37 +0300 Subject: [PATCH 3/7] Changed license --- TODO.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/TODO.md b/TODO.md index 24506d37..8a5e64fb 100644 --- a/TODO.md +++ b/TODO.md @@ -50,11 +50,11 @@ - [ ] **opendaimon-spring-boot-starter** — auto-configuration starter for easy integration - [ ] New module `opendaimon-spring-boot-starter` with `AutoConfiguration.imports` - [ ] Minimal dependency: `opendaimon-common` + `opendaimon-spring-ai` - - [ ] **Module hygiene & ArchUnit** — enforce clean module boundaries before publishing to Maven Central (see `AGENTS.md` § Project Nature) - - [ ] **`./mvnw dependency:analyze` reactor-wide** — fix every `Used undeclared dependencies` and `Unused declared dependencies` finding, then wire `maven-dependency-plugin:analyze-only` into the `verify` phase with `failOnWarning=true` so future undeclared / unused deps break CI. First known cases: `opendaimon-telegram` uses Caffeine in `TelegramChatPacerImpl` without declaring it (transitively via `opendaimon-common`); `opendaimon-spring-ai` re-declares Caffeine that already comes through `opendaimon-common` — keep the declaration (per "declare what you use") and verify nothing else falls in the same trap. - - [ ] **ArchUnit test module** — inter-module boundary rules (`opendaimon-telegram` ↛ `opendaimon-rest`, `opendaimon-rest` ↛ `opendaimon-telegram`, only `opendaimon-app` may depend on multiple delivery-channel modules), per-module layering (`config` → `service` → `repository`, never the reverse), and a guard that forbids `@Service` / `@Component` beans plus concrete `@Repository` classes outside test sources while allowing Spring Data repository interfaces. - - [ ] **`maven-enforcer-plugin` rules** — `dependencyConvergence` (single resolved version per transitive dep), `requireUpperBoundDeps`, `bannedDependencies` (no `commons-logging`, no `*-spring-boot-starter` in non-`opendaimon-app` modules to keep delivery-channel modules embeddable in third-party Spring Boot apps). - - [ ] **Continuation checkpoint: module hygiene / dependency analyze / ArchUnit** + - [x] **Module hygiene & ArchUnit** — enforce clean module boundaries before publishing to Maven Central (see `AGENTS.md` § Project Nature) + - [x] **`./mvnw dependency:analyze` reactor-wide** — fix every `Used undeclared dependencies` and `Unused declared dependencies` finding, then wire `maven-dependency-plugin:analyze-only` into the `verify` phase with `failOnWarning=true` so future undeclared / unused deps break CI. First known cases: `opendaimon-telegram` uses Caffeine in `TelegramChatPacerImpl` without declaring it (transitively via `opendaimon-common`); `opendaimon-spring-ai` re-declares Caffeine that already comes through `opendaimon-common` — keep the declaration (per "declare what you use") and verify nothing else falls in the same trap. + - [x] **ArchUnit test module** — inter-module boundary rules (`opendaimon-telegram` ↛ `opendaimon-rest`, `opendaimon-rest` ↛ `opendaimon-telegram`, only `opendaimon-app` may depend on multiple delivery-channel modules), per-module layering (`config` → `service` → `repository`, never the reverse), and a guard that forbids `@Service` / `@Component` beans plus concrete `@Repository` classes outside test sources while allowing Spring Data repository interfaces. + - [x] **`maven-enforcer-plugin` rules** — `dependencyConvergence` (single resolved version per transitive dep), `requireUpperBoundDeps`, `bannedDependencies` (no `commons-logging`, no `*-spring-boot-starter` in non-`opendaimon-app` modules to keep delivery-channel modules embeddable in third-party Spring Boot apps). + - [x] **Continuation checkpoint: module hygiene / dependency analyze / ArchUnit** - [x] Root Maven hygiene baseline - Spring Boot aligned to `3.5.13`. - Removed explicit Spring Framework BOM override. @@ -106,11 +106,16 @@ - Run `./mvnw -pl opendaimon-app -am test -Dtest=ArchitectureTest -Dsurefire.failIfNoSpecifiedTests=false`. - Fix real boundary/layer violations in code; do not reintroduce frozen ArchUnit rules. - Verified with `./mvnw -pl opendaimon-app -am test -Dtest=ArchitectureTest -Dsurefire.failIfNoSpecifiedTests=false`: `ArchitectureTest` passed (7 tests, 0 failures/errors/skipped). - - [ ] Final reactor verification + - [x] Final reactor verification - Run `./mvnw clean compile`. - Run `./mvnw dependency:analyze -DskipTests`. - Run targeted `ArchitectureTest`. - Run `./mvnw clean verify`. + - Verified `./mvnw clean compile`: reactor build success across 8 modules. + - Verified `./mvnw dependency:analyze -DskipTests`: dependency analyzer reports `No dependency problems found` across all jar modules. + - Verified `./mvnw -pl opendaimon-app -am test -Dtest=ArchitectureTest -Dsurefire.failIfNoSpecifiedTests=false`: `ArchitectureTest` passed (7 tests, 0 failures/errors/skipped). + - First sandboxed `./mvnw clean verify` failed in `opendaimon-spring-ai` because the sandbox blocked local socket binding / DNS used by tests (`MockWebServer.start`, `example.com`). + - Verified outside the sandbox with `./mvnw clean verify`: full reactor build success; `dependency:analyze-only` and enforcer rules passed in `verify`, including app integration tests. ## Agent Framework Pivot From 89fb1321512c511674cb63b07f0ebafcb869e5d9 Mon Sep 17 00:00:00 2001 From: ngirchev Date: Fri, 1 May 2026 17:42:12 +0300 Subject: [PATCH 4/7] fix bugs --- opendaimon-spring-ai/SPRING_AI_MODULE.md | 6 + .../ai/springai/agent/AgentTextSanitizer.java | 75 +++++++- .../agent/SpringAgentLoopActions.java | 2 +- .../AgentTextSanitizerThinkTagsTest.java | 27 +++ .../SpringAgentLoopActionsStreamingTest.java | 17 ++ opendaimon-telegram/TELEGRAM_MODULE.md | 5 +- .../service/TelegramAgentStreamView.java | 169 +++++++++++++----- .../service/TelegramAgentStreamViewTest.java | 51 +++++- 8 files changed, 299 insertions(+), 53 deletions(-) diff --git a/opendaimon-spring-ai/SPRING_AI_MODULE.md b/opendaimon-spring-ai/SPRING_AI_MODULE.md index 0964adb6..023d7417 100644 --- a/opendaimon-spring-ai/SPRING_AI_MODULE.md +++ b/opendaimon-spring-ai/SPRING_AI_MODULE.md @@ -541,6 +541,12 @@ never sees an orphan "⚠️ reached iteration limit" status line with no body t the warn message ever shows up in `logs/`, it flags a bug in the `handleMaxIterations` fallback chain rather than being normal steady state. +Final-answer cleanup strips model reasoning before both delivery and chat-memory +persistence. The sanitizer handles provider metadata, `...` blocks, +or plaintext `THINK:`/`Thought:` prefixes. If a plaintext reasoning prefix has no +clear answer boundary, the cleaned answer is treated as empty so the retry/fallback +path runs instead of saving or sending reasoning as assistant text. + ### WebClient codec — `webToolsWebClient` bean Built-in agent tools that fetch arbitrary third-party pages/APIs (`WebTools`, diff --git a/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/agent/AgentTextSanitizer.java b/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/agent/AgentTextSanitizer.java index a23ffd61..ed4ddd5c 100644 --- a/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/agent/AgentTextSanitizer.java +++ b/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/agent/AgentTextSanitizer.java @@ -17,7 +17,8 @@ *

Two related families of markup are handled: *

    *
  • {@code } reasoning blocks — extracted for the - * reasoning stream, then removed from the answer text.
  • + * reasoning stream, then removed from the answer text. Plaintext + * {@code THINK:}/{@code Thought:} prefixes are treated the same way. *
  • {@code } and its loose fallback inner tags * ({@code }, {@code }, {@code }, bare tool * names on their own line) — stripped unconditionally because they are @@ -56,6 +57,15 @@ final class AgentTextSanitizer { /** Matches a bare tool-like name on its own line (e.g. {@code http_get}, {@code web_search}). */ private static final Pattern BARE_TOOL_NAME_PATTERN = Pattern.compile("(?m)^\\s*\\w+_\\w+\\s*$"); + /** Matches plaintext reasoning prefixes emitted by some models instead of tags/metadata. */ + private static final Pattern PLAINTEXT_THINK_PREFIX_PATTERN = + Pattern.compile("(?is)^\\s*(?:THINK|Thought)\\s*:\\s*"); + /** Common model-authored boundary between plaintext reasoning and the answer. */ + private static final Pattern PLAINTEXT_FINAL_MARKER_PATTERN = + Pattern.compile("(?im)^\\s*(?:FINAL(?:_ANSWER)?|Answer|Response)\\s*:\\s*"); + /** Blank line boundary between plaintext reasoning and the visible answer. */ + private static final Pattern BLANK_LINE_PATTERN = + Pattern.compile("\\R\\s*\\R"); private AgentTextSanitizer() { throw new AssertionError("static utility, do not instantiate"); @@ -64,11 +74,12 @@ private AgentTextSanitizer() { /** * Attempts to extract reasoning/thinking content from the LLM response. * - *

    Two sources are checked: + *

    Sources are checked in priority order: *

      *
    1. Generation metadata key "thinking" (Spring AI Ollama 1.1+ with think=true)
    2. *
    3. Generation metadata key "reasoningContent" (OpenRouter/Anthropic)
    4. *
    5. {@code ...} tags in text output (older Ollama or custom models)
    6. + *
    7. Plaintext {@code THINK:}/{@code Thought:} prefix blocks
    8. *
    * * @return reasoning text, or null if not available @@ -94,9 +105,11 @@ static String extractReasoning(ChatResponse response) { var output = response.getResult().getOutput(); if (output != null && output.getText() != null) { String rawText = output.getText(); - if (rawText.contains("")) { - log.info("AgentTextSanitizer.extractReasoning: found tags, textLength={}", rawText.length()); - return extractThinkTags(rawText); + String extracted = extractThinkTags(rawText); + if (extracted != null) { + log.info("AgentTextSanitizer.extractReasoning: found reasoning markup, textLength={}", + rawText.length()); + return extracted; } } } catch (Exception e) { @@ -106,8 +119,9 @@ static String extractReasoning(ChatResponse response) { } /** - * Extracts content from {@code ...} tags (Ollama thinking mode). - * Returns the thinking text, or null if no tags found. + * Extracts content from {@code ...} tags or plaintext + * {@code THINK:}/{@code Thought:} prefixes. + * Returns the thinking text, or null if no reasoning marker is found. */ static String extractThinkTags(String text) { if (text == null) { @@ -116,7 +130,7 @@ static String extractThinkTags(String text) { int start = text.indexOf(""); int end = text.indexOf(""); if (start < 0 || end < 0 || end <= start) { - return null; + return extractPlaintextThinkBlock(text); } String thinking = text.substring(start + "".length(), end).trim(); return thinking.isEmpty() ? null : thinking; @@ -132,6 +146,9 @@ static String extractThinkTags(String text) { *
  • Close without open: drops from start of text up to and including {@code }. * The open tag was lost (stream corruption, upstream sanitizer, or partial tag emit); * text ahead of the orphan close is reasoning that must not leak to the user.
  • + *
  • Plaintext {@code THINK:}/{@code Thought:} prefix: drops the reasoning block. + * If no answer boundary can be found, returns an empty string so the caller can + * handle it as an empty response instead of leaking reasoning.
  • *
* *

Diverges from {@link StreamingAnswerFilter} on the orphan-close case: the @@ -146,7 +163,7 @@ static String stripThinkTags(String text) { int start = text.indexOf(""); int end = text.indexOf(""); if (start < 0 && end < 0) { - return text; + return stripPlaintextThinkPrefix(text); } if (start < 0) { return text.substring(end + "".length()).trim(); @@ -157,6 +174,46 @@ static String stripThinkTags(String text) { return (text.substring(0, start) + text.substring(end + "".length())).trim(); } + private static String extractPlaintextThinkBlock(String text) { + var prefix = PLAINTEXT_THINK_PREFIX_PATTERN.matcher(text); + if (!prefix.find()) { + return null; + } + int contentStart = prefix.end(); + Boundary boundary = plaintextAnswerBoundary(text, contentStart); + String reasoning = boundary != null + ? text.substring(contentStart, boundary.reasoningEnd()) + : text.substring(contentStart); + reasoning = reasoning.trim(); + return reasoning.isEmpty() ? null : reasoning; + } + + private static String stripPlaintextThinkPrefix(String text) { + var prefix = PLAINTEXT_THINK_PREFIX_PATTERN.matcher(text); + if (!prefix.find()) { + return text; + } + Boundary boundary = plaintextAnswerBoundary(text, prefix.end()); + if (boundary == null) { + return ""; + } + return text.substring(boundary.answerStart()).trim(); + } + + private static Boundary plaintextAnswerBoundary(String text, int searchFrom) { + var marker = PLAINTEXT_FINAL_MARKER_PATTERN.matcher(text); + if (marker.find(searchFrom)) { + return new Boundary(marker.start(), marker.end()); + } + var blankLine = BLANK_LINE_PATTERN.matcher(text); + if (blankLine.find(searchFrom)) { + return new Boundary(blankLine.start(), blankLine.end()); + } + return null; + } + + private record Boundary(int reasoningEnd, int answerStart) {} + /** * Strips raw XML tool call markup that some models emit in text responses * instead of using the structured function calling API. diff --git a/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/agent/SpringAgentLoopActions.java b/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/agent/SpringAgentLoopActions.java index 74b736ad..ce18b90d 100644 --- a/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/agent/SpringAgentLoopActions.java +++ b/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/agent/SpringAgentLoopActions.java @@ -260,7 +260,7 @@ public void think(AgentContext ctx) { ctx.setCurrentTextResponse(text); log.info("Agent think: final answer, length={}", text.length()); log.debug("Agent think: final answer text:\n{}", text); - messages.add(output); + messages.add(new AssistantMessage(text)); } } } diff --git a/opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/agent/AgentTextSanitizerThinkTagsTest.java b/opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/agent/AgentTextSanitizerThinkTagsTest.java index 123b884d..5511c134 100644 --- a/opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/agent/AgentTextSanitizerThinkTagsTest.java +++ b/opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/agent/AgentTextSanitizerThinkTagsTest.java @@ -18,6 +18,13 @@ void shouldReturnNullWhenNoThinkTags() { assertThat(AgentTextSanitizer.extractThinkTags("Just a regular answer")).isNull(); } + @Test + void shouldExtractPlaintextThinkPrefixBeforeBlankLine() { + String text = "THINK: I should answer from the previous context.\n\nI already answered above."; + assertThat(AgentTextSanitizer.extractThinkTags(text)) + .isEqualTo("I should answer from the previous context."); + } + @Test void shouldReturnNullForNullInput() { assertThat(AgentTextSanitizer.extractThinkTags(null)).isNull(); @@ -46,6 +53,26 @@ void shouldReturnTextUnchangedWhenNoThinkTags() { .isEqualTo("Just a regular answer"); } + @Test + void shouldStripPlaintextThinkPrefixBeforeBlankLine() { + String text = "THINK: I should answer from the previous context.\n\nI already answered above."; + assertThat(AgentTextSanitizer.stripThinkTags(text)) + .isEqualTo("I already answered above."); + } + + @Test + void shouldStripPlaintextThoughtPrefixBeforeAnswerMarker() { + String text = "Thought: Need to be concise.\nAnswer: The answer is visible."; + assertThat(AgentTextSanitizer.stripThinkTags(text)) + .isEqualTo("The answer is visible."); + } + + @Test + void shouldReturnEmptyForPlaintextThinkPrefixWithoutAnswerBoundary() { + String text = "THINK: I should now present the answer but have not separated it"; + assertThat(AgentTextSanitizer.stripThinkTags(text)).isEmpty(); + } + @Test void shouldReturnNullForNullStripInput() { assertThat(AgentTextSanitizer.stripThinkTags(null)).isNull(); diff --git a/opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/agent/SpringAgentLoopActionsStreamingTest.java b/opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/agent/SpringAgentLoopActionsStreamingTest.java index 04de2e11..4cde354e 100644 --- a/opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/agent/SpringAgentLoopActionsStreamingTest.java +++ b/opendaimon-spring-ai/src/test/java/io/github/ngirchev/opendaimon/ai/springai/agent/SpringAgentLoopActionsStreamingTest.java @@ -177,6 +177,23 @@ void shouldPreserveNonThinkContentWhenSnapshotStreamContainsEmbeddedThinkTag() { assertThat(joined).doesNotContain("reasoning"); } + @Test + void shouldStripPlaintextThinkPrefixFromFallbackFinalAnswer() { + when(chatModel.stream(any(Prompt.class))) + .thenThrow(new RuntimeException("stream unavailable")); + when(chatModel.call(any(Prompt.class))).thenReturn(chunk( + "THINK: I should answer from prior context.\n\nI already answered above.")); + + actions.think(ctx); + + assertThat(ctx.getCurrentTextResponse()).isEqualTo("I already answered above."); + assertThat(ctx.getCurrentTextResponse()).doesNotContain("THINK:"); + assertThat(events) + .filteredOn(e -> e.type() == EventType.THINKING) + .extracting(AgentStreamEvent::content) + .anySatisfy(content -> assertThat(content).contains("prior context")); + } + @Test @SuppressWarnings("unchecked") void shouldRouteFallbackCallThroughPriorityRequestExecutor() throws Exception { diff --git a/opendaimon-telegram/TELEGRAM_MODULE.md b/opendaimon-telegram/TELEGRAM_MODULE.md index 36bdc108..ea39f0b9 100644 --- a/opendaimon-telegram/TELEGRAM_MODULE.md +++ b/opendaimon-telegram/TELEGRAM_MODULE.md @@ -600,8 +600,9 @@ answer. ### Length handling - status message rotation uses `TelegramProgressBatcher.selectContentToFlush(...)` -- final answer uses chunked send when text exceeds `maxMessageLength` -- split prefers paragraph boundaries; oversized paragraphs are hard-cut to stay within Telegram limits +- final answer uses chunked send when the converted Telegram HTML would exceed `maxMessageLength` +- split prefers paragraph boundaries, flushes the current paragraph buffer before overflow, + and hard-cuts oversized paragraphs so every sent HTML chunk stays within Telegram limits --- diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamView.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamView.java index a34bbba6..91562fac 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamView.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamView.java @@ -6,6 +6,9 @@ import io.github.ngirchev.opendaimon.common.service.AIUtils; import lombok.extern.slf4j.Slf4j; +import java.util.ArrayList; +import java.util.List; + /** * Telegram view for an agent stream model. * @@ -129,29 +132,52 @@ private boolean flushAnswer(MessageHandlerContext ctx, TelegramAgentStreamModel return true; } Long chatId = ctx.getCommand().telegramId(); - String html = model.answerHtml(); long maxWaitMs = telegramProperties.getAgentStreamView().getFinalDeliveryTimeoutMs(); + List answerChunks = splitAnswerChunks(model.answerText()); + if (answerChunks.isEmpty()) { + log.error("Final Telegram answer split produced no chunks for chatId={}", chatId); + return false; + } Integer answerId = ctx.getTentativeAnswerMessageId(); if (answerId == null) { Integer replyTo = ctx.getMessage() != null ? ctx.getMessage().getMessageId() : null; - Integer sentId = sendAnswerChunks(chatId, model.answerText(), replyTo, maxWaitMs); + Integer sentId = sendAnswerChunks(chatId, answerChunks, replyTo, maxWaitMs); if (sentId == null) { log.error("Final Telegram answer send failed for chatId={}", chatId); return false; } ctx.setTentativeAnswerMessageId(sentId); ctx.markAnswerEdited(); - } else if (!messageSender.editHtmlReliable(chatId, answerId, html, false, maxWaitMs)) { - Integer sentId = messageSender.sendHtmlReliableAndGetId( - chatId, html, null, false, maxWaitMs); + } else if (answerChunks.size() == 1) { + String html = toHtmlChunk(answerChunks.getFirst()); + if (!messageSender.editHtmlReliable(chatId, answerId, html, false, maxWaitMs)) { + Integer sentId = messageSender.sendHtmlReliableAndGetId( + chatId, html, null, false, maxWaitMs); + if (sentId == null) { + log.error("Final Telegram answer edit and fallback send failed for chatId={}", chatId); + return false; + } + ctx.setTentativeAnswerMessageId(sentId); + } + ctx.markAnswerEdited(); + } else { + String firstHtml = toHtmlChunk(answerChunks.getFirst()); + Integer lastId = answerId; + if (!messageSender.editHtmlReliable(chatId, answerId, firstHtml, false, maxWaitMs)) { + lastId = messageSender.sendHtmlReliableAndGetId( + chatId, firstHtml, null, false, maxWaitMs); + } + if (lastId == null) { + log.error("Final Telegram answer first chunk edit/send failed for chatId={}", chatId); + return false; + } + Integer sentId = sendAnswerChunks(chatId, answerChunks.subList(1, answerChunks.size()), null, maxWaitMs); if (sentId == null) { - log.error("Final Telegram answer edit and fallback send failed for chatId={}", chatId); + log.error("Final Telegram answer trailing chunks send failed for chatId={}", chatId); return false; } ctx.setTentativeAnswerMessageId(sentId); ctx.markAnswerEdited(); - } else { - ctx.markAnswerEdited(); } ctx.setTentativeAnswerActive(false); ctx.setAlreadySentInStream(true); @@ -159,48 +185,111 @@ private boolean flushAnswer(MessageHandlerContext ctx, TelegramAgentStreamModel return true; } - private Integer sendAnswerChunks(Long chatId, String answerText, Integer replyTo, long maxWaitMs) { + private Integer sendAnswerChunks(Long chatId, List chunks, Integer replyTo, long maxWaitMs) { + Integer lastId = null; + Integer currentReplyTo = replyTo; + for (String chunk : chunks) { + lastId = sendAnswerChunk(chatId, chunk, currentReplyTo, maxWaitMs); + if (lastId == null) { + return null; + } + currentReplyTo = null; + } + return lastId; + } + + private Integer sendAnswerChunk(Long chatId, String markdown, Integer replyTo, long maxWaitMs) { + String html = toHtmlChunk(markdown); int maxLength = telegramProperties.getMaxMessageLength(); - if (answerText.length() <= maxLength) { - return messageSender.sendHtmlReliableAndGetId( - chatId, AIUtils.convertMarkdownToHtml(answerText), replyTo, false, maxWaitMs); + if (html.length() > maxLength) { + log.error("Refusing to send oversized Telegram answer chunk: chatId={}, htmlLength={}, maxLength={}", + chatId, html.length(), maxLength); + return null; } - Integer lastId = null; - String[] paragraphs = answerText.split("\n\n"); + return messageSender.sendHtmlReliableAndGetId( + chatId, html, replyTo, false, maxWaitMs); + } + + private List splitAnswerChunks(String answerText) { + int maxLength = telegramProperties.getMaxMessageLength(); + List chunks = new ArrayList<>(); + if (answerText == null || answerText.isBlank()) { + return chunks; + } + String[] paragraphs = answerText.split("\n\n", -1); StringBuilder buffer = new StringBuilder(); - Integer currentReplyTo = replyTo; for (String paragraph : paragraphs) { - while (paragraph.length() > maxLength) { - if (!buffer.isEmpty()) { - lastId = sendAnswerChunk(chatId, buffer.toString().trim(), currentReplyTo, maxWaitMs); - if (lastId == null) { - return null; - } - currentReplyTo = null; - buffer.setLength(0); - } - String chunk = paragraph.substring(0, maxLength); - lastId = sendAnswerChunk(chatId, chunk, currentReplyTo, maxWaitMs); - if (lastId == null) { - return null; - } - currentReplyTo = null; - paragraph = paragraph.substring(maxLength); + String candidate = buffer.isEmpty() ? paragraph : buffer + "\n\n" + paragraph; + if (fitsTelegramHtml(candidate, maxLength)) { + buffer.setLength(0); + buffer.append(candidate); + continue; + } + flushAnswerBuffer(buffer, chunks); + splitOversizedParagraph(paragraph, chunks, maxLength); + } + flushAnswerBuffer(buffer, chunks); + return chunks; + } + + private void splitOversizedParagraph(String paragraph, List chunks, int maxLength) { + String remaining = paragraph; + while (!remaining.isEmpty()) { + int splitPoint = findMarkdownSplitPointForHtmlLimit(remaining, maxLength); + if (splitPoint <= 0) { + chunks.clear(); + return; } - if (!buffer.isEmpty()) { - buffer.append("\n\n"); + String chunk = remaining.substring(0, splitPoint).trim(); + if (!chunk.isEmpty()) { + chunks.add(chunk); } - buffer.append(paragraph); + remaining = remaining.substring(splitPoint).stripLeading(); } - if (!buffer.isEmpty()) { - lastId = sendAnswerChunk(chatId, buffer.toString().trim(), currentReplyTo, maxWaitMs); + } + + private int findMarkdownSplitPointForHtmlLimit(String text, int maxLength) { + if (fitsTelegramHtml(text, maxLength)) { + return text.length(); } - return lastId; + int low = 1; + int high = Math.min(text.length(), maxLength); + int best = 0; + while (low <= high) { + int mid = (low + high) >>> 1; + if (fitsTelegramHtml(text.substring(0, mid), maxLength)) { + best = mid; + low = mid + 1; + } else { + high = mid - 1; + } + } + if (best <= 0) { + return 0; + } + int preferred = AIUtils.findSplitPoint(text, best); + return preferred > 0 && fitsTelegramHtml(text.substring(0, preferred), maxLength) + ? preferred + : best; } - private Integer sendAnswerChunk(Long chatId, String markdown, Integer replyTo, long maxWaitMs) { - return messageSender.sendHtmlReliableAndGetId( - chatId, AIUtils.convertMarkdownToHtml(markdown), replyTo, false, maxWaitMs); + private void flushAnswerBuffer(StringBuilder buffer, List chunks) { + if (buffer.isEmpty()) { + return; + } + String chunk = buffer.toString().trim(); + if (!chunk.isEmpty()) { + chunks.add(chunk); + } + buffer.setLength(0); + } + + private boolean fitsTelegramHtml(String markdown, int maxLength) { + return toHtmlChunk(markdown).length() <= maxLength; + } + + private String toHtmlChunk(String markdown) { + return AIUtils.convertMarkdownToHtml(markdown); } private boolean reserveForView(Long chatId, boolean force) { diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamViewTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamViewTest.java index c9567194..c538dfc8 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamViewTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamViewTest.java @@ -35,11 +35,12 @@ class TelegramAgentStreamViewTest { @Mock private TelegramMessageSender messageSender; @Mock private TelegramChatPacer telegramChatPacer; + private TelegramProperties properties; private TelegramAgentStreamView view; @BeforeEach void setUp() throws InterruptedException { - TelegramProperties properties = new TelegramProperties(); + properties = new TelegramProperties(); properties.setMaxMessageLength(4096); properties.getAgentStreamView().setFinalDeliveryTimeoutMs(5000); lenient().when(telegramChatPacer.tryReserve(anyLong())).thenReturn(true); @@ -89,6 +90,54 @@ void shouldDeleteStaleStatusWhenFinalStatusEditFails() { assertThat(delivered).isTrue(); } + @Test + @DisplayName("flushFinal should flush paragraph buffer before answer chunk exceeds Telegram limit") + void shouldFlushParagraphBufferBeforeAnswerChunkExceedsTelegramLimit() { + properties.setMaxMessageLength(120); + MessageHandlerContext ctx = newContext(); + ctx.setStatusMessageId(STATUS_MESSAGE_ID); + TelegramAgentStreamModel model = new TelegramAgentStreamModel(false, false); + model.apply(AgentStreamEvent.finalAnswer("a".repeat(80) + "\n\n" + "b".repeat(80), 0)); + when(messageSender.editHtmlReliable(eq(CHAT_ID), eq(STATUS_MESSAGE_ID), any(), eq(true), eq(5000L))) + .thenReturn(true); + when(messageSender.sendHtmlReliableAndGetId(eq(CHAT_ID), any(), any(), eq(false), eq(5000L))) + .thenReturn(31, 32); + + boolean delivered = view.flushFinal(ctx, model); + + ArgumentCaptor answerCaptor = ArgumentCaptor.forClass(String.class); + verify(messageSender, org.mockito.Mockito.times(2)).sendHtmlReliableAndGetId( + eq(CHAT_ID), answerCaptor.capture(), any(), eq(false), eq(5000L)); + assertThat(delivered).isTrue(); + assertThat(answerCaptor.getAllValues()) + .hasSize(2) + .allSatisfy(html -> assertThat(html.length()).isLessThanOrEqualTo(120)); + } + + @Test + @DisplayName("flushFinal should split by converted HTML length, not raw markdown length") + void shouldSplitAnswerByConvertedHtmlLength() { + properties.setMaxMessageLength(120); + MessageHandlerContext ctx = newContext(); + ctx.setStatusMessageId(STATUS_MESSAGE_ID); + TelegramAgentStreamModel model = new TelegramAgentStreamModel(false, false); + model.apply(AgentStreamEvent.finalAnswer("&".repeat(25), 0)); + when(messageSender.editHtmlReliable(eq(CHAT_ID), eq(STATUS_MESSAGE_ID), any(), eq(true), eq(5000L))) + .thenReturn(true); + when(messageSender.sendHtmlReliableAndGetId(eq(CHAT_ID), any(), any(), eq(false), eq(5000L))) + .thenReturn(31, 32); + + boolean delivered = view.flushFinal(ctx, model); + + ArgumentCaptor answerCaptor = ArgumentCaptor.forClass(String.class); + verify(messageSender, org.mockito.Mockito.times(2)).sendHtmlReliableAndGetId( + eq(CHAT_ID), answerCaptor.capture(), any(), eq(false), eq(5000L)); + assertThat(delivered).isTrue(); + assertThat(answerCaptor.getAllValues()) + .hasSize(2) + .allSatisfy(html -> assertThat(html.length()).isLessThanOrEqualTo(120)); + } + private static TelegramAgentStreamModel modelWithCleanedFinalAnswer() { TelegramAgentStreamModel model = new TelegramAgentStreamModel(false, false); model.apply(AgentStreamEvent.toolCall("web_search", "{\"query\":\"tickets\"}", 0)); From b82391f3a4cb075cff1b90839f39aef04dc23aba Mon Sep 17 00:00:00 2001 From: ngirchev Date: Fri, 1 May 2026 18:03:34 +0300 Subject: [PATCH 5/7] Added codex config --- README.md | 1 + docs/codex/config.example.toml | 68 +++++++++++++++++++ docs/codex/mcp.example.json | 34 ++++++++++ docs/codex/serena.example.yml | 29 ++++++++ docs/codex/setup.md | 117 +++++++++++++++++++++++++++++++++ 5 files changed, 249 insertions(+) create mode 100644 docs/codex/config.example.toml create mode 100644 docs/codex/mcp.example.json create mode 100644 docs/codex/serena.example.yml create mode 100644 docs/codex/setup.md diff --git a/README.md b/README.md index 0fddaeef..184d66d2 100644 --- a/README.md +++ b/README.md @@ -711,6 +711,7 @@ File -> Invalidate Caches / Restart - **[docs/setup-telegram.md](docs/setup-telegram.md)** — Create a Telegram bot and get your user ID - **[docs/setup-serper.md](docs/setup-serper.md)** — Enable web search (optional) +- **[docs/codex/setup.md](docs/codex/setup.md)** — Recreate the Codex, MCP, and Serena workstation setup ### Project docs diff --git a/docs/codex/config.example.toml b/docs/codex/config.example.toml new file mode 100644 index 00000000..ce5a8698 --- /dev/null +++ b/docs/codex/config.example.toml @@ -0,0 +1,68 @@ +# Copy selected sections into ~/.codex/config.toml on a workstation that should +# use the same Codex project setup for OpenDaimon. +# +# Keep real user paths and account-specific preferences in ~/.codex/config.toml. +# Do not commit the copied file back to the repository. + +model = "gpt-5.5" +model_reasoning_effort = "high" +plan_mode_reasoning_effort = "xhigh" +service_tier = "fast" + +[projects.""] +trust_level = "trusted" + +[features] +codex_hooks = true +memories = true +terminal_resize_reflow = true + +[tui] +status_line = [ + "model-with-reasoning", + "context-remaining", + "current-dir", + "model-name", + "project-root", + "git-branch", + "five-hour-limit", + "weekly-limit", + "used-tokens", + "total-input-tokens", + "total-output-tokens" +] + +[mcp_servers.context7] +command = "npx" +args = ["-y", "@upstash/context7-mcp"] + +[mcp_servers.serena] +command = "uvx" +args = [ + "--from", + "git+https://github.com/oraios/serena", + "serena", + "start-mcp-server", + "--context", + "codex", + "--project-from-cwd" +] + +[mcp_servers.serena.tools.edit_memory] +approval_mode = "approve" + +[mcp_servers.serena.tools.write_memory] +approval_mode = "approve" + +[mcp_servers.exa] +url = "https://mcp.exa.ai/mcp" + +[mcp_servers.jetbrains] +command = "npx" +args = ["-y", "mcp-remote", "http://127.0.0.1:64342/sse"] + +[mcp_servers.jetbrains.tools.get_project_modules] +approval_mode = "approve" + +[mcp_servers.jetbrains.tools.get_all_open_file_paths] +approval_mode = "approve" diff --git a/docs/codex/mcp.example.json b/docs/codex/mcp.example.json new file mode 100644 index 00000000..3176e1d3 --- /dev/null +++ b/docs/codex/mcp.example.json @@ -0,0 +1,34 @@ +{ + "mcpServers": { + "context7": { + "command": "npx", + "args": [ + "-y", + "@upstash/context7-mcp" + ] + }, + "serena": { + "command": "uvx", + "args": [ + "--from", + "git+https://github.com/oraios/serena", + "serena", + "start-mcp-server", + "--context", + "codex", + "--project-from-cwd" + ] + }, + "exa": { + "url": "https://mcp.exa.ai/mcp" + }, + "jetbrains": { + "command": "npx", + "args": [ + "-y", + "mcp-remote", + "http://127.0.0.1:64342/sse" + ] + } + } +} diff --git a/docs/codex/serena.example.yml b/docs/codex/serena.example.yml new file mode 100644 index 00000000..67fc49e5 --- /dev/null +++ b/docs/codex/serena.example.yml @@ -0,0 +1,29 @@ +# Copy selected values into ~/.serena/serena_config.yml. +# This file is a workstation template, not a repository runtime config. + +language_backend: LSP +line_ending: native + +gui_log_window: false +web_dashboard: true +web_dashboard_listen_address: 127.0.0.1 +web_dashboard_open_on_launch: false +web_dashboard_interface: + +jetbrains_plugin_server_address: 127.0.0.1 +log_level: 20 +trace_lsp_communication: false +tool_timeout: 240 +default_max_tool_answer_chars: 150000 +token_count_estimator: CHAR_COUNT +symbol_info_budget: 10 + +project_serena_folder_location: "$projectDir/.serena" + +default_modes: + - interactive + - editing + +# Optional. Serena updates this list automatically after activation. +projects: + - diff --git a/docs/codex/setup.md b/docs/codex/setup.md new file mode 100644 index 00000000..47abf5c1 --- /dev/null +++ b/docs/codex/setup.md @@ -0,0 +1,117 @@ +# Codex Workstation Setup + +This guide documents the project-specific Codex, MCP, and Serena setup needed to work on OpenDaimon from a new machine. + +Do not commit personal global files such as `~/.codex/config.toml`, `~/.codex/hooks.json`, or `~/.serena/serena_config.yml`. This repository keeps portable examples and project instructions instead. + +## What Is Versioned + +- `AGENTS.md` contains the project instructions for Codex and other coding agents. +- `.serena/project.yml` contains the shared Serena project configuration. +- `.serena/memories/` contains curated project memories that are safe to share. +- `docs/codex/mcp.example.json` is a portable MCP example for clients that support repo-local MCP config. +- `docs/codex/config.example.toml` is a template for the relevant `~/.codex/config.toml` sections. +- `docs/codex/serena.example.yml` is a template for the relevant `~/.serena/serena_config.yml` values. + +The local `.mcp.json`, `.serena/project.local.yml`, `.serena/cache/`, and OS/editor artifacts stay ignored. + +## Prerequisites + +Install the normal project toolchain first: + +- Java 21 +- Maven wrapper support through `./mvnw` +- Docker, for integration tests and local runtime dependencies +- Node.js with `npx`, for Context7 and JetBrains MCP bridge +- `uvx`, for Serena +- `rg`, for fast repository search +- `ast-outline`, optional but recommended because `AGENTS.md` asks agents to use it for structural pre-reads + +For JetBrains MCP, open the project in a JetBrains IDE with the MCP plugin enabled. The documented bridge expects the plugin SSE endpoint at `http://127.0.0.1:64342/sse`. + +## Codex Global Config + +Copy the relevant sections from `docs/codex/config.example.toml` into `~/.codex/config.toml`. + +Replace: + +- `` with the real checkout path on that machine. + +Keep API keys and personal preferences out of repository files. If a server requires authentication, configure it through the normal global Codex or provider-specific mechanism on that workstation. + +The important MCP servers for this project are: + +- `serena`, for project-aware symbol navigation and memories. +- `jetbrains`, for IDE-indexed Java navigation and inspections. +- `context7`, for current framework and library docs. +- `exa`, for web research when needed. + +Restart Codex after editing `~/.codex/config.toml`. MCP discovery is session-scoped, so changed servers usually do not appear in an already-running session. + +## Repo-Local MCP Option + +If the Codex build or another MCP-aware client supports repo-local `.mcp.json`, create a local copy: + +```bash +cp docs/codex/mcp.example.json .mcp.json +``` + +The committed example uses Serena `--project-from-cwd`, so it does not contain a machine-specific project path. + +Keep `.mcp.json` ignored. It is allowed to diverge per machine when a local MCP endpoint, transport, or path differs. + +## Serena Global Config + +Copy the relevant values from `docs/codex/serena.example.yml` into `~/.serena/serena_config.yml`. + +Recommended behavior for this project: + +- Keep `project_serena_folder_location: "$projectDir/.serena"` so shared memories live in the checkout. +- Keep `web_dashboard: true` for diagnostics. +- Keep `web_dashboard_open_on_launch: false` so Serena does not open a browser tab on every startup. +- Use `language_backend: LSP` by default. Use JetBrains only when you intentionally want Serena to depend on the IDE backend. + +After the first activation, Serena may update the global `projects` list with the machine's real checkout path. + +## Hooks And Skills + +Codex hooks and skills are workstation-level assets, not OpenDaimon runtime files. + +The current local setup uses: + +- `~/.codex/hooks.json` for hook orchestration. +- `~/.codex/skills/continuous-learning-v2` for session observations. +- Java/OpenDaimon skills such as `fix-java`, `open-daimon-spring-patterns`, `springboot-tdd`, and `springboot-verification`. + +Do not vendor those directories into this repository. If another machine should behave the same way, install or sync the Codex skill stack into that machine's `~/.codex/skills`, then enable hooks in the global Codex config: + +```toml +[features] +codex_hooks = true +memories = true +``` + +Hooks should remain optional for building and testing OpenDaimon. A fresh agent must still be able to work from `AGENTS.md`, the Maven project, and the MCP templates. + +## Smoke Check + +From the repository root, start a new Codex session and check: + +```bash +codex mcp list +``` + +Expected MCP servers: + +- `context7` +- `serena` +- `exa` +- `jetbrains`, when the JetBrains IDE plugin is running + +Then ask Codex to verify that Serena is active for `open-daimon`. If Serena starts but the dashboard does not open automatically, that is expected with the recommended config. + +For code verification after edits, keep using the repository rule: + +```bash +./mvnw clean compile +``` From a7b96f37c5a5390353910f3940b86e9a7742126d Mon Sep 17 00:00:00 2001 From: ngirchev Date: Fri, 1 May 2026 18:38:43 +0300 Subject: [PATCH 6/7] Fix bug --- opendaimon-app/pom.xml | 12 +-- .../AppRuntimeDependencyContractIT.java | 89 +++++++++++++++++++ opendaimon-spring-ai/pom.xml | 25 +++++- 3 files changed, 118 insertions(+), 8 deletions(-) create mode 100644 opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/config/AppRuntimeDependencyContractIT.java diff --git a/opendaimon-app/pom.xml b/opendaimon-app/pom.xml index 8d07b1e8..46150ee4 100644 --- a/opendaimon-app/pom.xml +++ b/opendaimon-app/pom.xml @@ -142,6 +142,12 @@ minio runtime + + + com.squareup.okhttp3 + okhttp + runtime + @@ -246,11 +252,6 @@ h2 test - - com.squareup.okhttp3 - okhttp - test - com.squareup.okhttp3 mockwebserver @@ -293,6 +294,7 @@ org.postgresql:postgresql org.flywaydb:flyway-database-postgresql io.minio:minio + com.squareup.okhttp3:okhttp net.logstash.logback:logstash-logback-encoder org.apache.pdfbox:pdfbox-io org.springframework.boot:spring-boot-testcontainers diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/config/AppRuntimeDependencyContractIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/config/AppRuntimeDependencyContractIT.java new file mode 100644 index 00000000..ac5cdd0e --- /dev/null +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/config/AppRuntimeDependencyContractIT.java @@ -0,0 +1,89 @@ +package io.github.ngirchev.opendaimon.it.config; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import javax.xml.parsers.DocumentBuilderFactory; +import java.nio.file.Path; +import java.util.List; +import java.util.Optional; +import java.util.jar.JarFile; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Verifies that runtime-only application composition declares the companion + * dependencies needed by optional library modules. + */ +class AppRuntimeDependencyContractIT { + + @Test + @DisplayName("opendaimon-app keeps MinIO runtime dependencies on the packaged classpath") + void minioRuntimeDependency_hasOkHttpRuntimeCompanion() throws Exception { + Document pom = DocumentBuilderFactory.newInstance() + .newDocumentBuilder() + .parse(Path.of("pom.xml").toFile()); + + Optional minioScope = dependencyScope(pom, "io.minio", "minio"); + Optional okhttpScope = dependencyScope(pom, "com.squareup.okhttp3", "okhttp"); + + assertThat(minioScope) + .as("opendaimon-app must include MinIO for runtime storage auto-configuration") + .hasValueSatisfying(scope -> assertThat(isRuntimeVisible(scope)).isTrue()); + + assertThat(okhttpScope) + .as("MinIO constructs MinioClient with okhttp3.RequestBody on the runtime classpath") + .hasValueSatisfying(scope -> assertThat(isRuntimeVisible(scope)).isTrue()); + } + + @Test + @DisplayName("opendaimon-app packages Spring AI provider auto-configurations") + void springAiRuntimeDependency_hasProviderAutoconfigCompanions() throws Exception { + List packagedLibraries = packagedLibraries(); + + assertThat(packagedLibraries) + .as("OpenAI/OpenRouter models require OpenAiChatAutoConfiguration to create OpenAiChatModel") + .anyMatch(name -> name.startsWith("spring-ai-autoconfigure-model-openai-")); + assertThat(packagedLibraries) + .as("Ollama models require OllamaChatAutoConfiguration to create OllamaChatModel") + .anyMatch(name -> name.startsWith("spring-ai-autoconfigure-model-ollama-")); + } + + private static Optional dependencyScope(Document pom, String groupId, String artifactId) { + NodeList dependencies = pom.getElementsByTagName("dependency"); + for (int index = 0; index < dependencies.getLength(); index++) { + Element dependency = (Element) dependencies.item(index); + if (groupId.equals(text(dependency, "groupId")) + && artifactId.equals(text(dependency, "artifactId"))) { + return Optional.ofNullable(text(dependency, "scope")); + } + } + return Optional.empty(); + } + + private static boolean isRuntimeVisible(String scope) { + return scope == null || scope.isBlank() || "compile".equals(scope) || "runtime".equals(scope); + } + + private static String text(Element element, String tagName) { + NodeList nodes = element.getElementsByTagName(tagName); + if (nodes.getLength() == 0) { + return null; + } + return nodes.item(0).getTextContent().trim(); + } + + private static List packagedLibraries() throws Exception { + Path jarPath = Path.of("target", "opendaimon-app-1.0.0-SNAPSHOT.jar"); + try (JarFile jar = new JarFile(jarPath.toFile())) { + return jar.stream() + .map(entry -> entry.getName()) + .filter(name -> name.startsWith("BOOT-INF/lib/")) + .map(name -> name.substring("BOOT-INF/lib/".length())) + .toList(); + } + } +} diff --git a/opendaimon-spring-ai/pom.xml b/opendaimon-spring-ai/pom.xml index 1206e80c..8bc20f96 100644 --- a/opendaimon-spring-ai/pom.xml +++ b/opendaimon-spring-ai/pom.xml @@ -98,6 +98,22 @@ org.springframework.ai spring-ai-openai + + + org.springframework.ai + spring-ai-autoconfigure-model-openai + runtime + + + org.springframework.ai + spring-ai-autoconfigure-model-ollama + runtime + + + org.springframework.ai + spring-ai-autoconfigure-model-chat-client + runtime + org.springframework.ai @@ -326,9 +342,12 @@ org.apache.pdfbox:pdfbox-io + They provide provider ChatModel, ChatClient, and ChatMemory runtime + beans for consumers of this starter-style module, so source analysis + cannot see the usage. --> + org.springframework.ai:spring-ai-autoconfigure-model-openai + org.springframework.ai:spring-ai-autoconfigure-model-ollama + org.springframework.ai:spring-ai-autoconfigure-model-chat-client org.springframework.ai:spring-ai-autoconfigure-model-chat-memory org.springframework.ai:spring-ai-autoconfigure-model-chat-memory-repository-jdbc From 19ba74bed440c6379c0dcf654e96b819d5154876 Mon Sep 17 00:00:00 2001 From: ngirchev Date: Sun, 3 May 2026 17:36:52 +0300 Subject: [PATCH 7/7] Added starter --- .run/ManualTests.run.xml | 13 ++ AGENTS.md | 13 ++ Dockerfile | 2 +- README.md | 2 + Screen Recording 2026-05-03 at 23.28.03.gif | Bin 0 -> 756733 bytes TODO.md | 9 +- cli/TESTING.md | 18 +- cli/bin/setup.js | 41 ++++- docs/codex/setup.md | 12 ++ docs/setup-telegram.md | 4 +- docs/team/archunit-rules.md | 4 +- docs/usecases/doc-xls-tika-rag.md | 4 +- docs/usecases/image-pdf-vision-cache.md | 6 +- docs/usecases/image-vision-direct.md | 4 +- docs/usecases/text-pdf-rag.md | 4 +- opendaimon-app/pom.xml | 8 + .../it/manual/AgentModeOllamaManualIT.java | 170 ++++++++---------- .../manual/AgentModeOpenRouterManualIT.java | 149 +++++++-------- .../it/manual/DocRagOpenRouterManualIT.java | 2 +- .../GreekImageVisionOpenRouterManualIT.java | 2 +- .../ImagePdfVisionRagOpenRouterManualIT.java | 2 +- ...ithTextPdfVisionRagOpenRouterManualIT.java | 2 +- .../ObjectsImageVisionOpenRouterManualIT.java | 2 +- .../manual/TextPdfRagOpenRouterManualIT.java | 2 +- .../it/manual/XlsRagOpenRouterManualIT.java | 2 +- .../manual/support/ManualScenarioCache.java | 36 ++++ .../support/ManualTelegramTestSupport.java | 115 ++++++++++++ .../support/ManualTestPrerequisites.java | 68 +++++++ .../it/telegram/TelegramRealGatewayIT.java | 4 +- .../src/main/resources/application-mock.yml | 4 - .../src/main/resources/application.yml | 10 +- opendaimon-common/pom.xml | 7 + .../common/config/CoreAutoConfig.java | 7 + .../common/config/CoreCommonProperties.java | 33 +--- .../CoreAutoConfigMeterRegistryTest.java | 22 +++ opendaimon-rest/pom.xml | 4 + .../rest/config/RestAutoConfig.java | 6 +- .../rest/service/AdminAttachmentService.java | 4 + .../service/AdminAttachmentServiceTest.java | 10 ++ opendaimon-spring-ai/SPRING_AI_MODULE.md | 2 + .../springai/config/SpringAIProperties.java | 13 -- opendaimon-spring-boot-starter/pom.xml | 84 +++++++++ ...aimonDefaultsEnvironmentPostProcessor.java | 40 +++++ .../opendaimon/opendaimon-defaults.yml | 156 ++++++++++++++++ .../main/resources/META-INF/spring.factories | 2 + ...ot.autoconfigure.AutoConfiguration.imports | 6 + ...nDefaultsEnvironmentPostProcessorTest.java | 74 ++++++++ ...onStarterAutoConfigurationImportsTest.java | 46 +++++ opendaimon-starter-consumer-example/README.md | 70 ++++++++ opendaimon-starter-consumer-example/pom.xml | 144 +++++++++++++++ .../example/StarterConsumerApplication.java | 14 ++ .../src/main/resources/application.yml | 25 +++ .../OpenRouterRestContractManualIT.java | 84 +++++++++ .../StarterConsumerApplicationContextIT.java | 46 +++++ .../StarterConsumerClasspathSmokeTest.java | 121 +++++++++++++ opendaimon-telegram/TELEGRAM_MODULE.md | 2 +- opendaimon-telegram/pom.xml | 8 + .../service/TelegramAgentStreamModel.java | 7 +- .../service/TelegramAgentStreamModelTest.java | 9 +- pom.xml | 1 + 60 files changed, 1496 insertions(+), 265 deletions(-) create mode 100644 .run/ManualTests.run.xml create mode 100644 Screen Recording 2026-05-03 at 23.28.03.gif create mode 100644 opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/support/ManualScenarioCache.java create mode 100644 opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/support/ManualTelegramTestSupport.java create mode 100644 opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/support/ManualTestPrerequisites.java create mode 100644 opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/common/config/CoreAutoConfigMeterRegistryTest.java create mode 100644 opendaimon-spring-boot-starter/pom.xml create mode 100644 opendaimon-spring-boot-starter/src/main/java/io/github/ngirchev/opendaimon/starter/OpenDaimonDefaultsEnvironmentPostProcessor.java create mode 100644 opendaimon-spring-boot-starter/src/main/resources/META-INF/opendaimon/opendaimon-defaults.yml create mode 100644 opendaimon-spring-boot-starter/src/main/resources/META-INF/spring.factories create mode 100644 opendaimon-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 opendaimon-spring-boot-starter/src/test/java/io/github/ngirchev/opendaimon/starter/OpenDaimonDefaultsEnvironmentPostProcessorTest.java create mode 100644 opendaimon-spring-boot-starter/src/test/java/io/github/ngirchev/opendaimon/starter/OpenDaimonStarterAutoConfigurationImportsTest.java create mode 100644 opendaimon-starter-consumer-example/README.md create mode 100644 opendaimon-starter-consumer-example/pom.xml create mode 100644 opendaimon-starter-consumer-example/src/main/java/io/github/ngirchev/opendaimon/example/StarterConsumerApplication.java create mode 100644 opendaimon-starter-consumer-example/src/main/resources/application.yml create mode 100644 opendaimon-starter-consumer-example/src/test/java/io/github/ngirchev/opendaimon/example/OpenRouterRestContractManualIT.java create mode 100644 opendaimon-starter-consumer-example/src/test/java/io/github/ngirchev/opendaimon/example/StarterConsumerApplicationContextIT.java create mode 100644 opendaimon-starter-consumer-example/src/test/java/io/github/ngirchev/opendaimon/example/StarterConsumerClasspathSmokeTest.java diff --git a/.run/ManualTests.run.xml b/.run/ManualTests.run.xml new file mode 100644 index 00000000..6c737b18 --- /dev/null +++ b/.run/ManualTests.run.xml @@ -0,0 +1,13 @@ + + + +

+ + + + \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md index 07c76b9d..00a321cb 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -21,6 +21,13 @@ Consequences for any change touching `pom.xml`, public types, or shared APIs: ## Rules for AI Agents +### Codex subagents + +- Use Codex subagents only when the user explicitly asks for delegation, parallel agent work, or a subagent. +- For small, bounded side tasks, prefer a Spark-backed Codex subagent with `model: gpt-5.3-codex-spark` and the lightest reasoning effort that fits the task. +- Keep Spark subagent work concrete and sidecar: codebase lookup, narrow verification, or a small disjoint patch. Do not hand off the immediate blocking task if the main agent needs that result before moving. +- When assigning a worker subagent, define its owned files or module clearly, and tell it that other changes may exist in the same worktree and must not be reverted. + ### Serena project context - Before using Serena tools for project-aware navigation, silently verify that the active project is `open-daimon`. @@ -52,6 +59,12 @@ Consequences for any change touching `pom.xml`, public types, or shared APIs: - If you add or change a use case, command flow, branching condition, input/output format, or error path — update the corresponding doc in the same commit. - Docs live next to the module root (e.g. `opendaimon-spring-ai/SPRING_AI_MODULE.md`, `opendaimon-telegram/TELEGRAM_MODULE.md`). +### ArchUnit scope + +- Keep ArchUnit focused on modules with meaningful architectural boundaries: `opendaimon-common`, `opendaimon-spring-ai`, `opendaimon-telegram`, `opendaimon-rest`, and cross-module checks from `opendaimon-app`. +- Do not add module-local ArchUnit suites to `opendaimon-ui` or `opendaimon-gateway-mock` while they remain thin support modules without their own repository/domain/service layering. +- For `opendaimon-ui` and `opendaimon-gateway-mock`, prefer compile checks, dependency analysis/enforcer checks, and focused behavior tests when behavior changes. Reconsider ArchUnit only if one of these modules grows stable internal architectural boundaries that need executable enforcement. + ### Language in code and documentation - **Code, comments, javadoc, commit messages, and in-repo documentation** must be written in **English**. diff --git a/Dockerfile b/Dockerfile index 4cdea25c..baf1a4ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,7 @@ ARG APP_VERSION=1.0.0-SNAPSHOT COPY pom.xml . COPY opendaimon-common/pom.xml ./opendaimon-common/ COPY opendaimon-spring-ai/pom.xml ./opendaimon-spring-ai/ +COPY opendaimon-spring-boot-starter/pom.xml ./opendaimon-spring-boot-starter/ COPY opendaimon-ui/pom.xml ./opendaimon-ui/ COPY opendaimon-rest/pom.xml ./opendaimon-rest/ COPY opendaimon-telegram/pom.xml ./opendaimon-telegram/ @@ -43,4 +44,3 @@ EXPOSE 8080 # Run application ENTRYPOINT ["java", "-jar", "app.jar"] - diff --git a/README.md b/README.md index 184d66d2..2e1d4f74 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,8 @@ [![Spring Boot 3.3.3](https://img.shields.io/badge/Spring%20Boot-3.3.3-6DB33F?logo=springboot)](https://spring.io/projects/spring-boot) [![License: Apache-2.0](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/NGirchev/open-daimon/blob/master/LICENSE) +![Screen Recording 2026-05-03 at 23.28.03.gif](Screen%20Recording%202026-05-03%20at%2023.28.03.gif) + ## Quick Setup **Option 1 — One command (recommended):** diff --git a/Screen Recording 2026-05-03 at 23.28.03.gif b/Screen Recording 2026-05-03 at 23.28.03.gif new file mode 100644 index 0000000000000000000000000000000000000000..47fb8a5f615dc5b049fc82d85080af2ec95d2664 GIT binary patch literal 756733 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

rd#dd%kx=SernnJrUUP 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ⅇXZUs-Gr5&E7EfDV59J?Op$E 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 *oBq5{dWgz0^Nqw(KUl@p<5=rAlCZsq_ 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

n7Y#WhV>cMjSwQG35cygdmWtE7yV>dIt~T?jEJ$ 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

_5rY8*NhBEk4KBwP=>$sClMqu2q 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

PCB_&@hu{2LK>aStNB~ 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 #Wz6bOk0ns1|g`n>i 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 z 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%0DS7&yAOPT(4g4?{O0c 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

4My)-=89n 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%0Aw zZ)<}3?t8_}nRxYXmpRLVo2T6G_w6zwb%qs;Yc*i7D*UK-x|}Cb#rv09-I|Z4lb`uz(k# zd5XWT-e3qJ88HiJ`|xQsmfz-7KuEMV2u3jCq~pSfVkCyyLbj_kD|B!Hz10E)wg#NE z{W*K*j_pT*Aliy8EPK6by^eS=gr~1~K1vZRS%>w))fiVmqM`k0CBjC-H+)y5O0usv z-sa&7fhU1T*xR`U5=(?()OdzN$YBx91|)d20|e}|HB0DYEDaKQ@-{DAmk%wTFt5Z7 z;>-%9`A#Mgsl|hsL(ZZGg^(mGaAUEgIH+ctIB{RgQbUCl#tR_~fRM{~icvOO&A0{SjVnEE-_lT z`f{D4BIvw&b(BLGKRoOrXe$IFSsb?Cq9=|@Ohl0~;R^7+I7WaD3Tmtjgyq3vYa_y; zT1J?pGaS8)YPC3{@eMYnknkK%^e|7!*69WO@DCCd_sGf^#~v>{aTo!r_|*3RA#yQh zu<+5P&%*%2_7z|#y$@=&Z3L=tOk5FmAYl(7HVrZx0>}6U*+;-+5W=L$tysE>ty-WU z&}wGZ3G++3uq66QPkg48#daR2VYh3O;pI-9jh3WW)OZqR13-8wM)J6+ z>ry`z$cj#EY1?&SRHcI-5uS(|I2rp==WxQ>LI#?* z+$`%B_d$c_CS66z?>stmR{9t48-cJu*W*T-4Ou5~|NHyT%_Zxf@Rq&YTJfFsh&x7? ztVKWp%AP|p1?#fdrwOSAJKmfrRaRZ;B7dg8Bo<^1siwU0HKRh`x}?TMx-$d{qwLUG=QvFHY8tFb33Kv;;I;i(9fKEGJX zG7=E9MVqt~q##SZt3@Oa>jzxL$8CT!xYUx*aAVtWS(ZIU+Hu~%1758ct8ZUmF+*&* z^wOA{qcrOgA-*z(_*CB`bh{Bzwl{-9e<+ikA<^8B_3QWEioj>b@<{Fg9gEHLybm?< z5|Ph1!_v;HPsS+@=@pjTkIq4YzvZP*o+THTz!gtlY2yk3VK~+q2mYZyPIP{Ocu|nk zjX@qf41nGz7)catl$!wKy$>>iP^J40H;oXGdVYEv()8+q-v$G67E{j1Sv&x%O*rlXVLlktY3a$wV5iJtS&nXZ)ALTzaT}TKT@oWQD6d4EyO` zf=87lPYzK2CXtIJj%gN1+6Gd1NKcYnrGK^@V%7=JGo>yiO`f}mUg(0>&O)OwW9&wg zNw$(}?3H8yxTj=xKC@WrvslLih=;F?61`e4&K?Kp*)?!TjT)k7F#w@iY;|G1=Vcj& zTShmPPaFCN)=K~ zmSq7jQ(6_$dKL%_$LH_OTHMOoti}>u2$*u_lWEf5vBP2&gDMDMMME)4^|3{oFdVRL zo#ClWZ!lDQfx)vNhX(P;QMQQ6>(wpraU}^HWdq&jfmdSBl%cFP|ymm zP%pwS47?7`&o}`4BXa1Tx!#v1c$pg0Aj3s(WAx!zpOKi<2=Gw!V-=JXZBqg>EHjmZ zRKo`=gIGjomaSFNc{*baL7<$*evEP5YT*yr>1jQ&o zS!*G2bX2n8_S~jv7_u&)nh1zylfh?^95td;XDCMFiX}z|*4!nK2LRlw#^7_pI=Btf zmh|W`NOLIw-DYE00WjSGKt{kT(l!HyFyLRMIz=wZ90DHcj}k2UfNGhqx=etNql3tH zk-A(^st2$sS$?Ec9A+TE6sQlZ=FHRzgZRPZm`+tW?`k?2WySY=YM255Bmf{OX;rQM ztF>pf2E4DIiPh0*%dC=1uE*G7fy?pNPQ%un>}w0#%#H#qjK~wiCkeCQqDxJx0C~pC z;AeBe$0C>`klGtAsxPW$tgSrrCZ1{bF?n0j+d;5Nb&t#4*N=lSEw0?Y85mJ~e9aQ( z23t2?b`o_FhEVllJ|%r*FH9sHmU%1Lk`<1tzvuH*SoAhXh#-@@W!MW7+x;gwAFe=y z_ydIyG*k59Z7XqM%Qs1Ib|-O!KnROvTi~`QNw@?gl5aT3W9X{+ud;maFG4z+KC_ja zVG+&s14Tl8?JD=}{^7pC8Le|{;z9yAHh_-1J-t?Cp+kBkv!*i#;Nr9=8;Sslh8fY6 z0R<@0w>$O(oz{!&7wh#l38NG;dzh zcjy^qmGvpmzZOz(B^!+FWvnZ9fWMp(g)*c8pC&>0cHWCO6|0~y2_HUHMfj-rsky?D zV8T2Ql&s7hq1vF?U(ihwr3WSG#RmCns(Rorv_eS$firL$#ig>#eaG zOx%j3_r;pyNhs^qBV82>d0Ql=Z4;vJ>O;-WtFA}`elWIX@T9g97;0)sw;!aI7I!fk z=-UfLgvDFI!7efAz4_7(jENTunq{IMQZAUtrksyaIuv6xIV_l>dX@xZ(}HG(&CWw# z0`i%{dbr^xBE2*j`BJe(Zwfa#X6@)%2(d#k%FS#x3`C8yzH8T7m9CUkaYnlc$7r>I~mA7Jb zrqRO|M}eP&Im_y0@~T;(?>JBh`^yEu3#y0&cBh7C&R z0rR4HPNMV6UPv6-MC-4Bjxf5OFx>23>^}?W56CisStv;~x0aTbsq0rDZ^yMI$O2w_&LgFTzT20nI`?}M47 zpeDUJ@gCT~U9Hao+9w|u@h*X7o*x;m@Lji-G9TdBy{(wsVVE~8YkX;X$OA`k@$wNJ z2|p=8<;60sGGuqlVSd@vB@JIAo@+D_kT?YrEeg@t!)ylO<^aa^nxJ4=MIf>p*Cy+C z4wjl|uRP+@wkrcCN)8`sNF7$`3M=VRDWDbLO^{qSK}C|JZBsTHiwjh{rEyVhslX;a z-8@whT-3SErEnhueV*d?odr+@r_p}=G%}@5k^;2ynK`P{wa1t9daoQ`kFn%{9Uhhw z8D{pQ_^V(kj>|o2MalyOmVgXoUV8Q%{FYXufSY%)7$NaE^i73U$Fn9zo8PHc;!G>#q zpbfT$NCe1=O;|{#SyUW>X%xUgsr`rw$C?N$v{5h|g*aZP%JhNQZBR*uJ#+F2e%JW5 zr-b-RY%=fn*JQX2Wb1AtLPv){5vZYb<2i8TlOwj)k{zOL#;%pC8E-cI?Nv$vk%_eb>5{B5^m}@@4oK@R+Js zsM%ao%$!8bwM2q=L>!_kHeD(H=(#ZW{poGc>34D;eMJ$B4`-RB9pt5*dfXC(*qsYv zz7Uc}hEl-Q!sk}43ehU-# zX{Bb4Y&E^mN+sS_mCXNs3@OEVh53#ycg#Uvde#PJ>8;EqAU(3pc<3eluKee)aC{Kp z$0W~{)rX&5*JNJU(7;aVhH8lQ$(615PwfxaI2bY`0uw8M0j({+NN4C)o`b9J~JX;7!^AQ&f9Yl;?vt{2Z^~6i1g_CL2)RcX}-{h^OBcdRI=vRUib?^KEk%C6*@KZV9^y3mh`wTozQxQ;&y>lOhv{?iq3fe!3o5dxwqt}Af8;kEC z!McF4GoDDw$s&k#>#GJ)4@`?1tZ`v2BL=uNz466j!r_DCnJ9yx^Km=^sD%Bs<&(#~ z;aG%hRx78rgYjhiPM`kSUZ`7XwR-M2na?gfKj@HInHCZy^92(=Rd3H!9~#2iXvK=q z0;I{3C&C^c1H!a0;6^pvq{>ASzbn--!wgBqWIK?)dP%-;iH!ht3}i5rGE(8vXCQJU z@C$%44rUnpjzR9RgPAz)UIHzr*DoFn0sFK<4mpA~A53H%mBdQi2~2F>M=?Pb5H|4k z{XFFkGx-s!Pl}qyEj)(K?A$x4QDln{0Ncuoz-$+}Q6mxvrrd^5X8-_T>Ulu8G^q_@ zAeONQULMVohlB&BB1rwzm=ZjgLqH9I3L^lj+eYHE-MU0@*S<4M+$D!GzWEIX0^N*o1+X*89mWSn<@1QQ5_pwC(# z#{GN0Kj9XGDsP!pr73D`pW1?#~gC z-E6aFW!e&$0?V50AB~?_2dxKQTR;60NKB*Ev&)>v^|}Hdrp5@--dx&zx3%dq5p@22yu}0Nr{sq zP6>|Sl+CGP^uJso4DhYF3C3dyKo{nDQr;x9ic3T$kP*p&>S2GdT8P zX;09mr35whvg(E7I-s`~-t>M@0@4@@DMi4L5O>;sSiW!+my!Mh6dsRBf`Z0i%ZK9v zTy}`}`@#L69D4o28?9Vw1}Ge2a@h8fA&~-+Z+cLX{-HQf@w~x>ek31_QMe)cnG)qJ z78EeaXeAqli4zot$r-l=5tf+4!+{Z##&P)jaj9YNpn(2?a8gDD29ejL2yK)+p7(qT z=_Cw-4GNQN;R+*YsTdGhVkg)$2#@$j?kqQ_taNh1)~8cY>cQT5Qhyb2m{5&5>a^lb2{uhQ7%#Xe*srOsJ}d)#Lai+Q=V_iXE3M9Nq_G1h5U47JO!Fc zgA%lt19c}Fuz-l3SyQ6wq-aGgdQps0hM?M9hq=U3}`Y}+DUCvlcOr#ra}RlQJ@A@s6)LdLf-@!m?CvB@GR*jXL_fTMzyCZ z6{#(83e~5&G^U;WCk(TMRdV{JrDLt?Hl>=(m;RKfYh`O&-3qv?25F;);Z!NHxvsJq zCagz_>s$T$SHK1qNrebTS1NJJ$Pm`5g`wSX7PJ`j^kDxCZaG%F%s@Q7x=BfW6>Mic z`&rN;CQ5WD!bc(z3jsuCgbPp%{2*c{zldQHU;_*cZlD4;fTga2!3|=1E4Vwsp$P*S zLm)u%+rY3kw992~bDfK%#=(*hs{sW$d?Acud}KAkIOTO$^O0k4H@n&$$1ylVUSAky z2WCp|6af<{M(kkLOM(;(M+joM!Ew~kwUfpK1@QlyP=2kpTPe`#iZA*=29~^rOAc`k zBd}u#W|bBhZGa*xaL^A>aGW`a1rDZL!jgTr1GcC|Ka)_@68!iU93O;P3)i899p*(E^igEdXkL!&O(n zL;SeMiEo6$!C`>HH_Af>L4ayk&Y9HgFjNY%#DQrHs_-slnAN*+b*vvPbi3XCZogeg z1d3+D0#5rPMwnvLS>lo&%iRTB&f(eXu|(k@*t*N3jlcFM5)B{gA5fBLOj{d zT_E%WRB-|UF9-q-)HkWE(P?|VT_{;?O4X-x7T!~*dex0&4NRn$-uAWxzV*F{XJo+# ze6U0%d;Atja~fkyDXsk*K+2ve~uDBFr+|-Iv4`TE%mhy zEWw865qcn7e|D1PCyM6R??Zkfo6DB`|0)K!CwR0EAaa zu@@1CO?ZXeP`Djbv4e7eD2g8|=mR?IGcO7NE>MF|fEYxuG9h>o9UubzLcA#3fsvRb z4G=Q}$sq_h4sdfCH3+aT8bkjMxSi00lRQ&1h=7(_34lWY!zqZ6kWiHR5RW6rQv?V|L^gD(Uh^ddi=QvKK~m(WRJ265&?Qb%gf9re6Pc}4{D>c6 zLmzmrH0s4;jDsUMMG{Q65;Vc2l0W&Zy>sIyR7xnBx+g|dM5F4c zol2>L0;ut`s-96t-+QNo+Np93Bx`&`ZR|&XWG-AdMt2OWluE0Cbh@ak$7}oxf;`7_ z3#f6l#~AvYU~)u>!Y2P|y2x`RCypekfBZ<0Y%X?8F3VU*#u!1YGAprKNq&SXb~H(_ zimG*6$+JpHltinPtjUnvNuC7Af9gq~3`(I)L2Dqj#bBJjh#bi%H+PwY1o;c597?I2 z%Ao9x#<-Hdu!Tri0mw+2!|)!z7`+sju=*IE$H1=_@QeGQO15lEkYus+0)X-Qi@5|Z zxx`AjJcjYoO0Ikiue7C={1aU3iW_KvJKzfu*Z~{ZEyidvar&*lJdBp4Nx*bV%e>6B z8V6M{FM3f0VSt6l(XJb##E%dL7o$XjVT4y;1YcMIz9fuEKnW}uj^hABEc43I+p?j6 zkR2!py5B~*3L>!1CP0BhFdqcT00p5Ij;I0}U;+GD1BxgBBp3v; z9FHw1g#~Dq7uf*htV2bp0X#4QC>XL0wF>oE9f<3K7qt*5n2!pTsC&W_u+|qL*gz_ql6`(P%%MEf-1yg_x z*#H27JDC4*;I3>y0}#8DFF1oL;DR+EOgn&2W;p{-c|WsQ0Mda*F<7+%qydR}k-5>O z7pgrPa0q2-ov*R;=z%}Eot5a*SR;{H%BqP< zfRO)Q=!IbzR*n56&GeDk0Dz7afqdf>VR(UKc!hDGjUKQD0!0G=@CCLxB}>>!Y4TKY zilJngwGDiEg1D=^Bh1AD}v`2r+$D1N4Al0x;s8|CVgYxW)@eCDURfJ4{*p1!W zbP)i*O)bf^gm54ekQj$FF@zWJPgtlN@klXPP*Z?01+uH01(;c7!Kqe438=8nHUNQa z<+A(vku#eJC^c6eP!MZjgC5BoC{Ti{u%vT!gCSVVd%YbnP=b9mAI-}EaLs^y{eb_b z$UQjpTpj@3^=P|;EZenRN3Q}tcoIjm?XY2x(vPTEL+ynso!fL^QYs6D3fYBFNK?KY z-z53lzeNmHCN#Yc+5zJ+9+w-qym~LnED(?;l10NVmR?siSiaNxmk%cNG?{yc1%la^3?w)Ua55K z$bO2*gWX6OZZ2V52#AG)ba*TS`+_SF;aiNK!2nz&9%RT+;`1#GUjU(Rgkq?R;(2^X z?kwXsETS7i%$1r45&Mcd>$t$)gq&h*t zXyhOb(vHljxKcN+^3nhGQFimFn9M0#F14EcMqDmPtpdpvSY=dhX5Uif%u+(kkmaQ! zX1#h6vHDKMkh&|TOd)LyZjNPGjl^YUW@kRt_U4it=WJ|PNL*rcp6BFJXCtL& zrQ%5?#%F%+3RM7YL7oVMn$>`SK3$*UG>sEX>So@%d# z>ZA^9u^wx(E^D(sYqU;lwO(tsZtJ$T>5ks$hKA;y*6Gx;Yr4j3ot|sHHsyW(Yrj5Z zz&_u=&g+H7>$$$`eNJq>ZfwVXY{-sm$)0S=u58PO>vP6wum~i zR_wi|X{Ro1!!B&kR_((kZP<=&*`96Mu5G!->_OJ-pU!Ka?(P4aK3)@+NP|(CyY9 zY~LPk*G}!_ChXPz?e{iq(Dv-~W^U(x@1^Ex?Cx*>{%-)+Ywa$lW4NwDhyepY@Ha>R z25)c&e{cwoa0#Dq3a@YlPjCdM18b;D#XxV=hVP%gZ@xZm&OT)2w(I>aZ4ifV;pT4^ zpKrrn@6K*+=f3X%zi}MTaru_+0SBeYJzEZ1=}KXd;yujw9lAc2#B1$S~dk8?Sn z^ChPP4i_A`{%|l)^F4oUE^qP3u5!d4bTQ|1LqGKYUULZgaSW$(M}KrkU-Gy-3@I0I zK?mF`$8>~l?EOye&~9qt-gFc9@(>qw;|_5Jb#aiMab`wzSAX^XR&)nCh69guTfg;N z|1P@9b6D?nU;lMr5BA}fbq1<+Tt9YXm-9&{3?(jynih6wk9KLFc2_6%1rmk_NOo=C zc1hp$%c=oRaQ42Sc5*Lwb3b?5w)O<_1vlsRMtApZrvtsJ(>>FXaqn|+WrJ{~Ke6cY@z`{Ur?c>WVWs!<_!?%ii~McW?iHpLmL2?11l^U}$$Gj|E642V0xc0RJU)N zN9>F5n@X?%3{Y~iOZt#^@=dS=rf+(YfAnQ<4Al1d)2{JA&ve4>>p@R(J@@NR=lUGK zbgZv<)}HP3_WH>#`o75l3TK2_K!!4?d%M4Ty2tydhqS2Idn11WxW{n7Z~DPcaKJBo zCpU$@Kk{cN<*55&$sazm-#V|Z^{RI%hzwnKlHON z^v8aGeGl`jfA~ySe-K~$)X$sM2Z#Xz2NHZ0$yPQ@oo3Bq#3-AkGJN=S0>lTIrG^zD zV&J226QMG12pYQe>({MQ;Y_0ZG~kz^BDADwyEUp1FJq%-K8Zol0MJj=ausR`^e4e! z0G2Xs>hx(-0aB+@tttS(RIFCFa?L7LtJkYttAe$PmFd^9V%KT~+cvFPxN7Ipt!wvg z*}Ho8@~xYedwMfBV#Ys_>N@rhw`HJ;3D zHs?H0>E*6}-IC2a81DDL;Kg$vzxF)gv`gg{Mt`+%c);?<#-DHhzF+)y%Wh|{7c+nX z3OFEv1sZrDWlUU>fOU*`23irVnYPeC6cG|q4zR$M%|sJfVBK^TJSWXL(p2}{NJ7Ol z$}PrF6O#dkoMMV|#_;k4DAYM;odwugrk#K0spZ{Q^@&H9k>~ZtR#;2&l_X$L>Nh2o zTeT-;djAO~SC;R^#T9~KiaGx#nPr-ZStTEG#t3N|h9==G2d&oJYHU971Rt=?A`(Uv zKzG3R()S^6IhZ&GcHi;y8LyF2Jsp%2P zB&wcs=utM#?lsg-Byx+|}}`dXPd5+quXDn+=N1DuiMU{OUEWprVl zw!8sSMVJg56fHLup$#Z>6i1YB%^AZC9mX!Bi7?eH11JW$P*V*`BJ#AOrao3S*IBFT z>*adt?F(kUMfS^`TWGz%BMMeLtqj$v?rer=NcoZusGda~6vNoDW>pt=!ffED^&7liF{6K}=S;$d$ zYJEKNJNA_LwVH~~HS5(|e?9iuzpg#^Yw!L&_~DZoEb-Etf4u>*=f}peiKL7(LKN#AiIRl%_l-DpRRS-Aw@uhj=9{ zV=2p7(z5@Sw!9@SZP|gw8~_ckTqQ7rDa>IKvzW#_CNh($%w;mOna+GBG@~iaX{wNm zLkd{|vZ>8&a{3bZVDb8_{vz+EUCpyy^PHM8Vo$iE~HT|Ni03bk}^}Htl?y1jx z^0S}*{3k#ID$s!vw4eq(s6gMT(1j*5o_jG9JtHd7iBhzp7QHA&Gpf;za4nzW(^0cQu{V7m8YSW<-b$>XO zSb^*r)TJ`DsZK3GQKKqV+#MCE15)Z!v#Qmtigc=8{pzo(YB2#}m8)hwYcJ7CPq4DJ ztz`ca>sSF)R<$A&s&l0)SKX@Dy#@%balOns(XdS@%ipC}_hj1(9P2wD-0_ z_yUWsAch*0R<@i7!HU5kV%U}f3wG#kce_yIHJlg%Nl@`p;_wA2uVJ%4P(l}=(A~|Z zLCSE5Kp3jv+1);w#c)uuAVRPdDO7AzJSagRG;jwpL_rQlAOaiAAcZ=BKoZp*gBskcfmhSIv33YSyj>dy z86X1IE!Z&4xn=)0I87kFc9#0KeTre-$+9yR_^lMgB9j;lQ~62TLLtsK=mz< z!U%i-`odD&>PyLd&y^qq7g*upp>4wub|8jMO2WlkAi^3{5Q-OA9qUcdE)vEY1hY38 z3`z(!xUVn<>vtdpD=sh+Ho$^651qy77K9#5-v)436yN}<9bOk~Kxy?KYgNIHC0`(H z8v`I8x{X@@-GB^C-x6Q}e)WOILE13HUIaXvUExA1*ck2+Lngq1?(v=rN|o>Z2Vhy0 z@U_?a)d2DNfDJs{1EPTtIAClQo8e7CA3#ALeA;S>mJ2A}7ySQ#3VZ=1_#7t~+XuKo z*116%a95f&*#TyO3|xT}6d?roL4)NJ2&f!|EnE`>LA14jBCws?T>%gbK^Ph#v~l1a zBA%c{6a&^l6!ak74Vn!2fT%6S2b2IA@IWclp`58!$`zIh?t)+?)*}!@KB1hLsoXlf zASVu03>pUTO%$>D5{LzWxfvk{umBX?z{4fM7a|+6>6;F;T3X$}2jsyS3|j>30CydN z9Mr*5>{=q8TK(yO6g0sO++i2q01oh&5KNi|YylJ)K?8`J5dayt)m_m^!m#0h6$soK z{F*980daAG3ml+!vB4LdRv-T1J7rN9qpnb={$2h4ziK|%^> zTO;~d2%rEKwBALsmJOgDxy1nz5LX}6!4A{`Zm~dg#TFM}WJxB$h#f%*>;O3)K?h*j zVckHR2^J?{K_`uYG#=STx&UsS*-}6yMiS#{0ReHf*QiOs4OATVapZ%o8V-bk5sX+8 zSb<4;Q!1>WQGUS*D#9u#LI4bdM(#pg#=)ee+#!TQCX`n2JtSc=R7A>CCK|v&=f)(abK+G#ohEgTr%-vPdP);`W|4TJCw#^yP^~9@ zMpJw8kf+HfdFm%jt(*hYCxAZFeVPS_Sr~sFsA9!ufG%h=4QO{r281Ojf=(!UGN^?z zQ$&UbgmzPa)fIL6=Xr*xh>oZ_U8spJlkYhZek#TY@}UHE7>trAhl&%3$|#A}sEvZt ziS8(d!j)nWs7mpukPa!47O9aQDUv3sk}m%#lb#a4JPefj(Z__4iUtzi*v&PeMU-kO z6A_Y?s>j2Kg&}c_At@4Ki0PCzshX}S4aJHUIjGsdjufRSo7QRg9D^@dgKu~XpZ2Mr z{wbgas-O-kp%$tzSc5Oz(XQAIe!MB1T8w+zsigLe7U*gE2n(iWs-|u#r*^8Rek!Pj z>L&RD9zE)SPAaPEjWxJX5w&Utk*b)O>Z7JAt@g?>(1EAAs;*uT9cTf9gw5K>Do)iZ zv6cxgkkPItD-0N8-SVqO8c>{a%oPo+z_#qZzzyHttlwg7xDIU2UTk=hEzdrzbv%eIlq^P= zEKraG(8`8SAnhw)NaRZH;GF;MC|nMTgl-Z!2PiPZjHHM*xP8s3v~d;q0oUY9EUbogQ485Pq>S`5QXsAuVeu$0_*PwW$f3=Y`BVT zrw}lB7;txtE0Iubd%t$fyKClJM$=hNuBZR}{elTaO@bg52J46HEG*1i^!V7Q9&*%u_2oZ~P zOHQmUkJvC|0I$@}an=fn?dtCE265F^kqY5KL zKSt{$3Bp)xm+=4aA1AOpS1df=4=4^Z!>aN?*vT7Ug3B;32H1>1Xs@-r!Qfag&)C95 zKyN``1o-MgHMqobRP;HZZnm^6(uXb(S!>=^xo6BAF&)W*=7@6YH0a8wN^69hH1$WXK|EfDo6Y(`0Nax^T% z7^6>0HwIoXknH45Fl$&&hb#jOQH3CK+e++Dx3MupM^#s~RZ~x++A{(f%)w69R~K?x z2ldk8b^W?^>XS{J=>odptwG09_$U1;v6ETzCNAqR zHqSbCu15bh#4gdw7V)^sDrWob{b=^sGQm!Jw!1!d48UqD11UV|P-*jWJfSuNAA)Pk zEpPX>Z~r!M2e)t!H*o`ZC3KP@`wwhmb;JB9>J)EQpAEwxap`QVtxySW=d^B@F0yvF zcYil{hqri-HyMdT-p*GfO_CjDH+vIn7J!mCNRoWdH+|Q)ecv~J=eK_EcO{6!Gjvj7 z_);kKcY7DOfgd=6C%A$yID_xbay2-FOKOJlN{&|ej9NH`XE=vOII6ZMMA6lDg4Amj zm+mR1Mro#Mj<|{AC{uB`ou2BLz$lAn)QqE5jn9-zQCM@jxSGPLN=;^Ku2hYxcuSEu zg^vFxk1wgI>Qsz=6p`onjjLuzMfs6Kd6FBcuqM?;MVMMqc~*^hhq@+$UU`u!Hi48A zJ~#vEg=m2xd5$+-5}d&qus|CS)|yW!nG306n`wg3cs}(*KTM%u@|2hB=YTZ;q9^(g zNaLN4d7hu>p7VKR(D(tU862zuKES~d@MWPJ7Hc}!qBT{1X+WZvI-)Nkn3;HNYIs9F z`h`Y%fQ(ZwECa3I<{Z#^3)q;5>9}aFW^ny_aODe;aG(0lqIgzPmuNpVkN@pAuq$j=7nZu{wQOdw^oQq(25g0e~~0gFDEBJ9Ilg z$b&qf18Ft6U9qG@aXbPH^Z9D#v+ccFa2!&_sO zyki3UM2Ug2Gdr{2T7jtm3eaKCjX@mnpbLzeYLz@=cG9?)XSq+Be8G{t#HC9jq7=;AAMMK{Rfp{na=R^gIg;U=8e-3pD=#Pm9pd!5fBXrUs?B)u#Al28W)iY;B-GejC z!#ucyIc&o=m_z!`gBaXHxygVa5Z(tgfEi>#AY5LNp&D_K<=XM39{8HEk=BRB!5iki z21LN*;g-3znHc;4)-AyiPC@Z;+)i=89gJIj>DaD4;7fKv`2z%m0|5vQ1OT95LK0$> z;At>K&clZd)eQN9FyV+beKddp00aw;Bz<;7nA8WO!c~1BtV)9>)gdM>0X$+?GfmB5 zIzOgLsgU47p+kulHF^|jQl(3oHg)Cj3sj7Ex6(C*xsBeE(kZmje~|bWSHbR z!X{j!loXVZgUotIm|@O>q~OAcK@ees2q~bmZ3@{GX@mcVcCUyDP!u2Wqcg=iTM3~| z)`)-|h709S(~dp<803&e9vOg7O+FdruR@&=BWPSM6`q%&an(=9et7JKGcw3l3Cprj zVP_4JtL)ccqZNWlLnSN4h0|nHqPHMGz(KbveY>cQsc#sPI2nH6L5?SLl~K59tR8rfGVv9I1aKCj4q%BEI*V2P(+{)$%SirJ$PE@|I#sV4W z3tVi8f5$lk7K8$rNTF?GgmKq$G#C`Wp{;@v{DB6C^0*R`4}@v6UTIu#29%s|f2Skg zcA(=y62QfI%PW))6LN??=&&e_j5z|Y;cMyyy2@L)vn$FVT>FkV;Qr^vJHZaY!~F(D8oX6sDg(K$_hm#Mnygnj)wn~<09*pM@wE3lbNInA313Z1fxz zLn%p9O0krWRHY&@xJpKHOp~#cCO|kQuLNQBJ!dMi6XfvM)Rp>$)N=kn|6rvF&5I{L; zlmj~Db5A+wMmgG1kA4)SAr zPI=l>pZ*l6L8Ybum_k&c9u=ucRcilIIY+>fHC3hq_0&_Hx>T!PwNl4W;8wZXRj+;( ztYH=FSjk#ev-;u~mdYGeo!Azs9x$L$B@0&RTG#$)l@1qpLku3!R}1_Vuz?lqUx%%TMYu%G?5DCz+)j2kxXTqUX-~UX>Yf+9=~XXlb?cvYf>$k`g|CC=Yt4gr zmo4MfFJ1GxUjP0Vz_k^IdyD_8-MRYqWcB?ncMptUPz4vbpxy6;lUm*YUl_vyenwY9 zYfJe)IKG;FZ-Etb-}u7U#ABiGihtT%3}l!BFqZLot*aI6!WEzj#_x_#%wiwo^cahs z@sNpJ+d>SG$4Q>)MIjUx9k2DrQGRJKAY0@ZTN%r)twdJPf?@}6_Q^|DGJU07=7{FN z0JObC1u9?&LzJP)&W)@gO!49?qd5nlc(a^8v1d7(7teS8bC!+FW#As#z+N%xeV;1O zMVr{sjyCY56P;p3V{X!tu4$v2$W~8tn#oO8v87WyP&1#JpU;T%Yv-_pb6DXVr!WRD zo?z$Lo+B5vW-};8fsFqr&>|YTZml%tP>9t2c@({7bD9B7=w$~wwl&_AW=rn)GAhxmV-P(K4+StCnM8TP@n(T({G7Le7S_?cCIpD=AXmN{7p!pMXxCJj#kZZ^?gI=`m z#V;Q2ja!_98FV0aB@CepP!wVnPhUkLe!&Jgc;gaPzlGJ|>{@N;LKnn|TpziMuu!SP^r{OHOW+XWH6^SA2H6J?bwv9>n54{BRL0 zT$jTf^RblqYn6}+LyUs&U}pm@43P^t#G(jGFh=Pc!1QIK{mthHw$nk;^-oNF8M%JM zGLpRvwVy*5s9yru`%dvR8{!tczD1w+K8oZIz#FmuMJ#R+^}3s)_=5&T_4iGS6Z{?U zf=3zTMebYhCLZJ~2e+3YPkxkd+tb_5wB!$e{>jq|$j`s4r%wPD|u zf$s1?7N4N&9#Hn^0O{y%87_g?Y%m_^?EjoD>T*F3Xz&(z4hLOp6ui&ov?1y~kOr^L z6s)el2J*B9lCP3c8um~J_mQ?7u_`ua2}Nzw!maTx4JMh8(?AW=YEmZiE5t_50Yp}{I3^y0S0*??qtu_eqj(#KpGOz4Dl}fgi!v5@Gt+N zFddUHCvlRu=1a$HQodrc%YxD|`-c?OE8)OT*qDt0DU+`*v*Gk@GF>Ycwh}C#;4_ml zvOx0}o{|}IfgA7a-SW;4`4YBJa+3;^CjXN0JkI_U@3_#Ba~{(-EoUg5O*kvF8!>aX zWOFKbQ#qFt!hX{^CkG7RaX6>5IE{0*zA-QXlR39@ou1P>BPTLplRC#!x{mA-xs$%o zQ>MO?JxPYjDvmtk6TPHOD%8_H)w4bGQ)I$ZKKoO;2B$vfiYNIf9L4bxDR2Fv@IDVy zKO6L8(4Z2e(?2Ivuf*XHg0m0+)G0>oD5_95El)wA>OdFNKtmL{927+#G(!Ks?+01b zMPC#~V^l_Gltv%RMsE~H6|3MZR4ATdMdOSAnR+QwL-nC1wL1d@p&ANRSxHn^^_)nRodD!iQ&m>!iB)TrmRvQ* z`Xg3nl~*yXRD56>ipF7q(~bH5sm9Ws8Alm4Ov@mTG@iUxRjNx3*G>)@XBSLXcKz>$MrG zR$d#S5pcl?x?vBRArY=tXPtl>Odw@jfoVy$8Lpuj(pCYIp%wp$MdY0ToiW zY*~SHITvM%VG&AKXB)w6YnNmjNpW*`w;1=k5Ed>T*JH&NYE7VWO#p58Ky#JBc%@bu z@|JHs7Z=dhd8@V&hF4y>VG)?O7B)8-XqOeFw|lF1bzxV0;nsQSHg7|=dQBE_b=Q3f zjCU)_cYy+UBi9k8K^D@sc)Ot%ARu|KK^CO8a#eQ^ptl%OH+8F47Uq^-U7;2Bz-*;9 z8Dh5??l*rMK^73Wc^!Cr-&Pqkmw*>|TSeh+57&*}7lr?0Dt`AAY=8F;#+Ghf;TpQZ za`(4?HMbd1L29uVaBIPGp*Ia)p`5abFm6>s5w5V1X0ihq-tW5@CcNm;hkc1Hb_laG`k< z;dI}&i2K$N;Mi}sHyK#riuu+Nn0H>umjviob6a766@Yy8IB;+Ggu~d9Q*w+uZGIJ^ ze$n`dGq{c4p^@`-dhb*9l;kj~Q5AMPV8sSQ(JEdkfi*kCj_w@*XN32bj9ke5+8TJck z=dgdMp${8pCEKpidao~Axxjj`O`s24U=C1V16+U#ZeS21re!z4NL=~~uD}G|p@rT- zteInkC|f4T1A^%qYYhprcYDG#8-_We2Ev2255c8jyP+Z2SDF|AN+DrxI%JJ|4`kc8 z*+BuIn+jw@2TZ%VC)=zoo43FFs(ky5J7Y6mKq#W1K4u^cJX;VDf*n9x5<(!gO@J8Y zCA*to3?^m=T0jtbAP8=N4A|j3R$~WtfCYpE1OlNna3Hi*gSN3&kic8QM@zhi0=U^> zwXqujZ1VQaV=a1;3jEspb5C;3Si(6H~_;zKq!Q!f>b~S zM4(zg;Beq0zKKRQI{dwbzzuLf2i`$8>fjD<$Silc@C z&+W!A2tCTBO&|BoeZj_#$!DSV!RaC1UL%a4QQYb*g*s=od&2NC)_}1 z{G-!99octkqljYEJ3|J-+*(muswkSB3Pxfm(%~Zfz29Gm1$1DwZ(=CA zO<(IhH6=-sWeX=eM-xivksJzUPO&PFcz*z(MGVUg_b~=nbkH zmLBQ}RhOck>gRNr42p!RUhCO&n~36qOovLFDJec4hDs=z-e~N}e(Tr1r-CU9-X89| z=~d{^*(LzV83op6_o8?6W{00$=b4Umvodl>li|p9zu3ew;4V-W}gv`d;$U zsZjJGAO3+JGGFsGKOfZL@N);RBYf@~KaMzN?IN{pZhNf_&uQ=!e9K`ffV+k0oDN++F|*Z12tHn37Vh^j$i>IKRrYrFp!Ce-so9P zsQUo|fWUzS3mQC#FrmVQ3>!Lp2r;6>i4-eZyofQQ#*GT!sq+LZq)1@@8tfBkFHZpg zS)jgG~TEdiW>+6b4R~0RjjtiZm%vqd~QFV0zO5P@*<*O?ApK ztJbYtyL$Z!HmumOWXqa8i#9D-k04341?DLOx^^g4vV@XB3K=p-^q5&Np^cFbQ&sU>&KtE1BSh!vqbC8$W1#(7**n9f5LMLXh|miZ0Hh*N zC=igL-vX-u@J%{l)O28xMjnY|l1eVgBv-nTvQ7i^09Q|h!=-dog*+MYgN6e2pn@13 z9$^{>oP5B>c1R$>Qkw)B<)%Rlu!EyOYwV)qo2K0dK{}ZblZk3g4oYaDh8~J&qGCNs z%03O~vCmsq=8@$HQ1qms4I~OxM->x*KqiSQc1CJNt00$SCc}J5P%7!v1ZXI!^rvX8 zw%&?suDTM)sDg7@=@yoEg@~FJbFhSi3w^KvLLXDe5Gu5pLJc+_}la4jWvt z004+^BGAG;Trmd{I83sVM7`|N#}NRek;)`T+y}s_6FhRN#y6(3?0fO9%yP>vzf9n~ z2f>%mzWm+{Qa)0&Nm&3nQ570hJ^uuB(cuv_iK>r0;;f&Kgj(^^VPpc?ne;6rGt63V z&2`saOC&(nda6@1&Nt^HY)8c%u$0i`xgBR{aIQU-Wd#8RA5(b8U69yc{|$KHg1Z~` z3UcPHPU4C$zSz*@Db+L3lNBYN-IX1U5w?B%J$UDye-65lg&z)|&yU3Xdg!*_j(hH}74A3WY)b}w-VVs^`s%MA?|bZ&@x9Rswd)Rj^wLj{5$|Hp zZoJ+>Yk$0Wt*frQ_mpep{PWbGkAC{-Tc0)dm6@(O{Ia(_wCs`7&k_6T@6Uh#ptBz~ z%Xv?Jbju$7@P@zy(oKO2EKc+E=f4O_aDpxaAn&pe0X2*oH$af(!|A_SX=#Vl%(HdgGS7rzL`DQN$3Fg%k0rFDArFa2umLa&m1Ef;9|_4wN^+8vtfVC` ziOEcAa+93wq$Cpw%CP{DYsxF7DNl*YRH|~7tZbz#UkS@t%5s*pEM6#Y$(1W=t(Ls( zr7wR8%wP(0n7zcMF&}8YT@rJd%xtDJp9#%i9&?%&;ax&XxvOYubDP}krZJ+Ct84^Hxeezc9tfxKiiBDd>bDsx^C+VaD(0~RMR{|BJKo5#g zsTee&3~i`G9}3ZkN_3(Wt*AvWiqVW}^nLv7XcEO|f{==Iq#?bVNDKc((v+%nr6cVO zOJ7P-m%>!0CoQQ>VT#k7>U5_(?Ws?H3e=zq^`#B%s8J1v5M?wX896No0iLRWs48F} z1dz>CB_h?VYIUnz?W$M53f8cSb*yA9t69&A*0id1t!!Ou_>2nIgDArhPS^t#po-VL zQWdH)B^6%*#k)f}DmLlfNFhu0fDdh|v&qmhtpAl)DWf>P4m_BOglw~mmK7@>lI zjucUmQb3UgK?FfTF?e`+zyHDc<=p3-``n-F61^MU;A*~cX-HDNH6ysmON42D)GVew zzq#p}Qu_SsfS8W*-6r23{5@T1h3Mvef}0-leV=1NZN|0cKs_vbAIyhw7Nq~*E@^9sT|Zs6&K&>O$I7k^g0@0vx*Xu5ciLuNpL)UctO{+DH? z&MaZh(K531oLQd~0#B7mf{M0SI_T~bRMtdzdg}+b-NnKIL&f%-Y(WpEtH%|5=XaBM zSJJi~6SyRa%BhxuQ=TT=&u-c%r?2cx{WsRh*Ro}#5~rKlv-fKVK>U_hZT?Z<$?u_h zDBMygV_kRW`rBLYn{tbo&F=EmynLzNe?ur|Q_rINl~q@}U0~%#;On^&w=3bw9Ln3j z9-meXj#so1-;`(gmtW^E_K~fdJy6t}0^zbU;HXGg(9sio>LPt#x z173)x|NZ!eHM%VjxEfflQycN_QQx=BZ}1;aXOp~NPZ!fcpT7QQ5Tl&s=70C{`lZ6-e4u;CHF@o}$Ky|4 zU1k08cCTzH+B;*j_%EDA-~+pm5`S^JAK7yS#0kM(fiReE1&!vN6E{XAttZiX8r6mkJ(haU;PGN@uPk1A3vxek(ZeD zl|!yBko~`H&^ByVDEP=H4!9F+HFT?bAv)x+?^*O|cNTBe&)0!hc7sB1 z@&(`dA<6087xhbHku793Al;2?+9{!;dN<)hXBD?)s}?!%AbR%Z-!GR>uPl_UJ`9|*U@8iAR&o2-+-lX1Z{3A3O}e%x=pFqy0{ZOl$P5`opr9oYn z$GST4_WX&aCs4WLC##t^{C0EK`# zxY9Dm{Vh9fDtN&Yevu;M4FIIILH`>C>sFq@ML6}b;E?6)h3^?^0Kivl_G7VZF@JJi zd}M86w#WpG90p~KPZr#VRU?>r;rEo_*G8xK-Zzh01!9_xT1p8rBMLxLhcPv zOm~{bggkZ`WHiBdn~oJ~NW*M{1c(KWFKzF>Bv9c&zqF76sKTrM8J-LPM=EG@5-_cW zBq8&Ix}i!~umqjeZ9;xxH0KPqtlQe?h@81W#zWt z=QkY)p{JpQ{=XlA&`FlRzt1$`_o1cdfi9=Wb|RJK3-wVIbsZ0N_)X;ws7xh*7^5o%#wyLp zdb2fp0bvhNQOv- z;wfu=L*X<=w9^VQNgHYMz~p5t@_{mt>kB_Atv3D~l&iylkMV)UAMJ27f-_88%mJLP zTvrJNn*NZqvjN{uz!#XD)@$4-hORU;n;|<*zTFS$@MTihBd@J7vEo-2H6A)Ggw4+SJ31Kp}VGunkLdB-;dnuO&4W{Cqx$wR5 z>J&^PjNpR>tpnkFIIgS`PECd^HQR^cG}T~oGDjmMG!pEOtZy_EX0tDZ9TXbdg64lq z$nVn_e+c2G!Tfx6H={c`$uJ4I4w!8_^+VmnpVkT4jyY+khDd(pkCIyGPOA-Yczj9e z@6Ovdz=2bz5;=dsXtal-n|3Qn<_Cz{hFej!jip z?mSO>5(frrpdkYBF!ON8ZTCiZENIk2ER51@jp3{4M`eoHpE3#|=nNb6h$2y4KXio) z5`?2Z$&cU-$8pKhC8rvJp{p2JDqJhIM2nsyg3PtHeQG!f3&7?TM93sPdf0c9A5#Ll zt=bYC0Ua?x%IxR2HY%$mAUt#7c|^5&S)>>m<}BLus1%$0$^Zm}Ke_zSVOt5c-W7vU zQrriMy7Mo*l2w&42&c4_uQc?GX)mNVln`2%_@!(BP)e9Q+iwXB<=JZi&85E@Uq7D0 zojrR~ddG$-~ZVuFQ|J&=O#ddI+Tlkv7QUL!wm6|hq>ws1@RTAvBL;oWjv9} z3KLBu5ry7J7$`oc+#k!Sn=G#bRNTk7m4TexbGCZ~?{Uz#nc%>|Q=pR;(2F`MpbLqt z=PT`Qk^U+qKb5J7&8oR6c7q0y$BFq0f}nCjuU?@HCZI86oER)jbqai01q8IGTttEf zT$PJtUzyTJLjVwgiN^K?h!Szw2sa`hHlzvwU!?&{7(k=FGO-k(#PYz0(tiHe{kGYgAz-S&Ej|4qzD-Qs`_0n^&D=<4+mpBN(vYZe`9}IcgQrQ6C&UjWvNNy2$ zllm`E(S4K?3n#eqM_}{bY{O!(h>!`0d^1#1v_2LIQgesjL8p{`2U8m`Z&Oo4u;BKd zHXVl-HWM;Qd7wZ#L)^aT#W2ygD|v#{wv#dW$-q;Yp@j}x_c{px#GnGYw=i~xE_oIe zLN#F0nMcB@FkKH?&>)AKJ8ZoPqGSVQ)dLFXFsPk?lgz~S%W23kA$byrDRruR0Lo!r zwA}+FP0X5M^HlbQ)Bzx8z;lb>w?5yYEc-OP4M;6`oKoIoy(@T7Ca=~EVOWr~kgqqJ zhuRWfld(mzHt_L&7&B+X`xTgJCa*scvc3veM^Yka$_OEBo?Z(J@wNZN2OgpPtfq#O zTj#rio+tq_XLSv(pVhVopmSJWhVr5jdzUoznL2S14dA?~CtklT!6PH7cC(3dzF5Ok zQjeIWL`66S_aFQn`@%FL8@ynLJyjnw|8zUIZG94s%gCe9+BfAv`e=p>mRxxvCWgNB zFg-hhR*19#<)WTnr9qe`C`8h*P}7P$Ca-MjqdUv$Sx%bilOz@kRzZV>(x)7n!OFpJ zK5G$-wY6f4l10qi-Ee^qqko!&|o11INx@A;hWB%!&`YKT!-Y5-dF z4sp`;4%8Ki=uueEnM#<|g{-G-yw8F2Pdrz}uLsd}-?Qk=ok+OS-|LD)2=sD6^x}LQ zVB_@!nF;l!8H&c8LQqyiQzI){H_{|rc>?Zji( zQUG(ay~?p-5KrVBSU}Q#G3O)>mU#|bNfWwtFp?|-w$km#EH2gAu5Oia`tR?$>;o0) zpSVB0Q?mN1kh-XBm^D`nAJh5h7Dlta^4{ZByYT_oQIVnK({S^hLJwjG`36?+1OyHd z)n!=|`aO0aG~!GBBL5%Mh6)EvOKxawZni9m;J^*HKcr{u-F^dP(EA*nDXVmT(jFlB ze(JNa;+sKonFj>|ErBH~f(o1VRp<8}()P>7x4YK1Z7);QDH*IM zEalg~IHONNetlmqp9OIjzzqSDS8(VBe`$K=QW47`7iNj z09y)3YJJH0Wa9YNc$MxOBg(I>twJ1i@Dc(rNtI&pOc+N%amh4>X@*s_Bg#JqN?_qql61z~Rb`E`m&-3= z1H{cu)#d$e`R_wVX3y&lYVL$xUm47&pAmB!lcH15 zpU9z=FhswXVS%uyN7peiLuvn&J7v(xkF|?;l@<(sH1^ap8Gv>YgRTZReT_%HZx2Y; zXng9C!eUmOkb!sD3T>4LF`1O*THpwPfmYCKy*$7En05-Zr;KOX6m~Us3n-cy5E95v z(urCqL-QnsDY+f!X2z;Dhv3wjjJd*-^>%Zm=MYs3<-k%J8~g?*Lk1WGSWcJ2ameUW zBo~;NRo7~oGL@vu5|mhLx>lJq5@m5#2F(KqE8Uy+kSu~R<2JEQvZP}|j7P!L>Vn9y z{gk?FTIU;!-wydxR#F!oq{&o@+Qo}PEUh-GCZ7U19PgX0VNcIScF6;3(htAB*$)|> z%$PONwgg`gm*~GVrkhwLZl#y$W#jxU!QReBc~_MM?-=IAG;NYQJ?~h3fom@6!HMVl zNG1x;ECOjG?&fU15!1*aDKs+^IQvijnKE3m%RQdWNNXit%C%!$o6oOs#WArxZ6Zw| z2DPYV3;>&_srtm&JiKKS>zOWPR5G7!s`1i0fAaOQSINaQy=WmH(b=U`sHMyIo-yo? zkGtCl-@GW8M14|qZT$D=WMARZiN9ayp2_b@e|l_#O#Djy)BFDWvr$|vd~TrGS&?tG z&$ZsseEYq0)g1v-3w{ZhJT5%xq3JMetV&R_vBaI%e}r~_=jK1iJAvM8WD>c6daFj zkrS--fa;cQ+qJ`f77QsW(m9yb@;evawUYmVJrEbP2pj<+fuf^>6FgW_U%5|WY~V`i z6{k*JH8!B#{3{P0oS=pTHd)%Wk~uyO**rl@;!Gi4_;boNDC8J)ZY|fbHDF7Gr*Iq*^24u>lR=!KY%NKbN5l;K0N4M|_d46LoU#kll=y>=AS2{OEyjwNj z9mZatDHyU}dcJCzQLoE^i-1m)*>_jYUm^J4i3Y1DP+61!WIreRfII{PC80q#{!J%I zRjh!urTZo8rXDLio+@ZfxF)YTOVV=s&S)0LDI7Kd1E>L^d5A&QdmHe0c_LiZsb7kl zl)`dIJ@eVe!|dWPax(}v(=Ik%_lX3|*Tf9cYU46HCUWS5N<`d&Oe|d1oLTO6 zN)Ztn`XoupzesrA2NNcbFp^mgt&ll?gt)E}as@(g!Ni%fP!K-R$Y3k)ZSZ zK-0X5*CSQ?U;-uZoXU;lsj<@zN4~kUhSxfbl&~(k@)YR%Sq=V#g3u_82MUf*gZl2HXgRRLciWVAjtC?0QH{7^%+INSffbHcWefT82jNTqQLe(LOSN?^(QS)kMsS5kPol!J)SOh2@aBT z@y&|7^7vx=*Y*CEkJ@D)yF-0K{96q_nK5Y|P3m#7>^%N4&=)#ek!@3%?$%rQ zS?z~&+4aFI!e9RE>iaAGTRIKVj5+C}cUD>@YN#zeiRAg_I{Wt{pw4OKMpAg%;Kx-a z!LD8@tNpqYm!*X}r*W_J?u3?3|J|rE?|PI94`1gi|G50>Tvxo+!ODT|mX`6K$Juwn z@;)Nh%#&{n=s$~!dZ_!^(E7&A?eWkC1ECGZOP^-oEz#|7dp3Qgrr*5UJFH}LThx#J z`*G#UVe8G4Eh(>?3p*__-K}~Xcb0C>fLr$i*sgrOz4UaH(fWw~+-*-s^WOaA`Rhg4 zg)lb#dy^+E$8`lltB%igHv49e^6v`oTrxh#Y^@*LewT6-aJA?8H^n1zvhaa(sP@W_ z=3i~6y+0q+-P*rj6#X^p*~X)#-&?PmZ%xSwZ-Q!iwltNZ9vD22lhE(|u6FlkgsRA~ z?6<$O80)|B-|lVmz4&kSl-=s+Vc_#0^}KifO+WkhIKKSvQ>pXIm%bf&KVRH4I@SAd z^ZC~wecNLC-^6ey9X)^IpHY>2OU(8Adi2x1w0H7!e-F}gRdwI>=)ZWS_x2{Pe_EHR zQ}4Y1E-U^ypj;2h-1AShoAs9Ni$MK9e{sNd?a$`@i(Hkgs# z1)d=U@;%?gKNm?b2%XmYs`I#@AGIFHSI>Z^_@AhEM+R#hFiqxz?PxhZj^w?y(V2ZLf4A_tN0f(Oc&NWMTbV6|D!0@(oxs?x_MrG^Z+ z>uGQ>prpy@{^s3C5%uE5*h-L{lv}`z$wWSk@rlgkKc&To%#xfC40SWq%rU0GHh-%wa zz$ySFS0B%QTu2Hs7oKCj(@FhDP{4#`^vk~v<&#U=Vl}K6_u8&SD3dt=&ADcomi!53 zUqCx3dDTCnQafaJG*%pImWQZ)p({J%AV1?C&l84dn`6rfqxI<~@D?|>agEa!H1Zwd zCFel$KadjNUzi`n!;X;}DJh4dSp!4`6(rCUS43V0HBj^T!ZMzr6+EjlF!n4KIyEW%FNM5MsMJDF zPw@fY-$>KJg7M*)mjN>zS_q>wj7I8=1vD4!N76undBLfA>fkK^3%eibGmY%q$**cc zQyXQ|)MC$H1&W`0$=?r>cxu~n>!oveEyotn;R{HW0z{+Z*C}#N!OEmg;Cl;mW%p?u z_w37Q{Gc~k#$A5F#m*E_H%YhC(B^pT3RIf_UN}zL12C&@3n%fB)BvqefE6Ct@zs^A zndsp48)2M-653)^n*&6TDG?t5le@$;=ZM-zuM7eaz}xl!Y+b1It8_--HZ3a@4@z8y zxQ@v!MR0#1&loHNxNOhXWBsE&#Xy^!Qks>5N;o)$w3G?WQn{Z^MzSQO&T6M1ya(XokLVP!Kj{~9dNS1UCWqNKI!?$hmfDy^`>5?=e9T{%lyx}r4$BS_< zz|$YJ&YAWvP%e*UGozZ=C{{`J>4Nhl?3|LY7DWW%dZ&p+pPyvYC54$Y|4qLviG4|P z0<*ZJaV$5paC~^(+`a3;>Dc|uY~JB^)0y-%VJ`<{zb&n{d~fQ=HrLsFte(fzLtF-t z$jkAGXUrBgTKcRzf7+jm^@ABafJNQo)2y0V{VlUg=g0}NlJW> zoz=yY0`;|Ndd{Q~qumniBW|Qx#ap++Af@oQ;OZ*_5wRH#o{c32p2;2XlQ~m1{zmH6 z{K4~oAElq;q@Ob^WYS{PSmE5`$Vz8OHC*9|S^1}2!V7LMpbRV27Zob=l#NpJ&@U0S zZSmVHg~Y`IglE~YiGs{(31ykrXY~mmg`J+o-t{T}n05JLXRj0Se3#@%P#)r9syZ?u z9|>liv-Adn1m|*Vuw>01hLy!BHx*$l!or>f#A>SF zD&aipuQ#j4F<|#lHR8HRiWBhCX#=y8QR?Xg!jG8@qXET;>pqFX_oyV^ijHJvlZf9h zoS7fmDth?Ir=GJ)r6kPcZN;aUcJoQ72tJam+DE;N9lSV36*azLmz!3n1|70Jq_g~V<$`grmDsuqwVL=pk=7r8T z=S;xTT}!+lKPb32DV`Q6W&MzR^e-YxR%|uFnaM``^3yCjB z%_Dw|nd|wGJx@Q|XZ|{6KY+CMNO(K9iKN%xV4^92rd3QL*)Utp*+Z>J0T*mbzr5!- zHyfl;z_h|L>Lz~mQ=sc78JaLeBgv?*9I{56_F88NF9o_!A+#b8NPwyyouuasen;QF zqXJSVLU<~qI`m{`x8k*r$viAx_z!vE!tv*wCbwkgr;_4Rspx!Gmdrx?>=WQ-K|;|Y zh^bow`)WS+PyPvFgIJ2lp0nhh6VIcY1x1ivQ$W*&YglcY&D-W9g>^|P!HuiM4X{w9 z92T=(Q}xrZmn~ld1dpWr$yrv3TwD2wt#Zim9mbL%A`3m9gOslD7hpLuHD{Iv(~3u5 zA=@XZo{~A*Jdxvb#k0g~gX1rrhAAr3Qgr-y*B!}%xR#S)LS}09Z(2<-x$=I0GeUvyn@}!!&G02N3TXBndvuTOg#_>M zy>H4tR*forbZL(0uFzIOf;k6>h2ADX2hUoJnG<*fJW_aY5XOoE*s0@1qbPM)d|%Z> zJmiC>{zwPZ9Yx<0=#hoR~gDUc+v^mWVU*?vHj{vhIjBN2WxG6-Q`b zr5J^p#H6z;K73dF{PQzA%fmalQ9*!JlhA0hNOt!O^}DPJtZU&_q{dR2PDf75|B`qk z+jV(Ul_SBref1jsFQLT>T%f5b(fuMAZJ@;~@Dbt~L}C0XSNI=L%(E1nA8?!;;A-Xk z6w1q}`h9zVQM3M6iXm{((<$A$Jqew~^NmeBF`?zDIOC%@7vqCWI8f)>XW}0i>!}{3 z;)H>nXva_aZga)!zUDFSaT2~*j!D!HWh0~K9z;ogO}!+Vykw>s2V84msoeY7e1Ew6 zKZH!!=eqhIFd9ffI_>C68Tg?u61gAaxS-G#st!<0fdhI31FI+I|5Hp4cicXKq{33J zrvOmVqCK}%2OjyLy;Bg0tmXB(-3xHpKWfSe{uAKidesyBpF?gccFtbE z#*0vO?d}(MM#`-$RdF1!<}Gvm?pNv7SDd?`qW}EkH)>N77+c_XOXnQ5Pj^<-5M*4A zp#HLi(*;w_q_qqf zfqXE)Mta?g<@EGlPVF)Ya>}A23hjgRW`;7mAuBAuB(0? zzo#G1s&GSXdyE++ouK?ZkquC9-D4DN^K(EL?j-9yVIV#-(-Et5I&)I?D`-T|sov&I z?(q&+j%DHi=?{Dl0AmsP%Q=9yb>Oh8U&;BzfqgSNo;-2&6+vrkTa5MK?&fWx^a$5^zaCf8i$ ztZQdY;Cqm7@6$ytkV7%V7dS-BKPb9N=Bq8%tW}O@HLAxZ`Czidp=Fo_54T`;nOPJU zvr5u}`$LBBgE>Kko3$B4&v5Q*L~Yn0+%^SUTb)hd-_AM3B9x6$u8_%*?BnL7WtgkX z`Utc91c1(+7dB?&29iwxSu^k_K;8KECwyS6KwsDDyo~@#Aro!vK5al0*w|75+j$tk zH*eF3=#yl6c*n)4$Egi_2n3jJf3@3Sp~wN#$D1Q8tQ3rYhU^1=M3Fc~tkI#4AgPD#PFh zTXYveRS2mbADj`e8U$2x^m%!~qa4mzj_`zy*f-Fi^+%032SM`IjuJai@$kX`KrrG3 zx6#+@6K~k?cJb^0LQ@57=NfkcG{1GE&?~itpHlX&sxohlBf{ejp3F&=UnlF^=;$ zvz~BGJ;Oxdy&|w?$2X{;Q>_9tLa%s;Ra7)t>z0i?O4n@pF){^{u!Z2$5@fr%H5i?G z7P3H)Hvc4{G{gF#Az}DtA58>+h?BOX00j*t7&N(97+gkE7^_X<*A6S05dY2s9VnPP zi3(ey6$#X$;b?dEi;?DDmpV;AYr~91adt5Q~tl3*k5cy*I=(-P)^E#j(_QfVyXa>Og zsvNgmOHaT6`n4zH&&c;B$xqyXg$*TmunHnR=qVMdI0v*N&_QRkD6q_ggK+mz8Pn7< zQ_$#^kr!91Z+i{&-TYf1BaWQ783OdvBAPTIr6h|z5TaBO69JAS9=dy--UYJ$neCVz z$5uJf>wkz0D}8i=WAr{ISqQhkW=S9y+6eXYf0&*ylBt5A>jzAZQNRlfD^Sm%ei#lw z?1)(oR+?D(szQW5)tGdlq+IIB4izh@Be)Txy3p5uYuyo<_z= z`ReSyC9S6zP$1?VxrC?8SBJ}rbJWxgRT_@<7i~Amfw!N zwliSOa3XPj)Z}=%R*OufOP%XE*FZ0if$KI67Kp-}my@Ro*}ZOT_V* z&|^_ND>0cNCF~-HasxrC)`9KvHqr98aqfx59-^yU6xFCQbFaZ2#vy-N^Ebd9+I+7v zSkB;0Nsv9L;{fgLdpyoDl>quyvjWpeG$aJxAR06s>64B}4LXZDCA>X=vCBjr$sGJ_ zB1TLg#ei$!36zT#7ZN=_;2$(*`f;0{so)gft2+gGW!WCb^ist1!-GLJ3x`-kdc6I5 zSfbh}MmcqdBOf}j~Suz+zD`pmLX zVudI<8|Ka;l%V|RVesz6oK>|nlFU^lb>(XnCPqKb%#t}*W;Uqb`rw4ktSgLX7zXlq zdN9TqN~EVc%t37su|i>#r_%Lk&Bh-^~s7Z_LvJwm* zBoAQWqw>|X0hJfptRM|Hx61WWhL?a0MP&u#Yy zTUh(!S9=JPXop`&;PqV&_HpvPfLzA1 zcmHnVq;^^X4$Cg3vY+=eZ8JZ^Cm|}M#wyYL*akNR_-ElSIq`&=d*v-2bXsUh{B#X}YT|pm)SzdexHlr?GSRUKD3Te52NVE96 zarHAsc$J}eOGp^%vkYS_hgB^)X1S6QH(|_ZhrVq= z{lvY*P_=yXt6R8(`!7r-cn^KR;t_`R0JosM1S=tbmf2y#teze`0T_xd)2;gDYt(YC zpD%drRwy`(f5sF~;|hPfN1`~V4J4cM3-wwJ-|1vc|GtG0--8vx@_1#9i2%qG%~+*V zLgF6W|9`hv(UsuTarc8a3`H~4mIM}a{Pr#y4eBj`6!WthHvYd^oQaN zLaGA)0i+xIxnF0_Effv4 zy$2L)2zWuf>|Bk;9WUz$Q}_Z<_}KR4zBxFh3JI+~xn-yDCuiB6uZ%47Wlhl=#2NM~nK){ZFdvWFN;A>gE057!8fY&`(>_6%px}U_?kibJnTPj) zMj}x8EXjj35Pd+lE|n}AdJjk7FT7z*IOZj&20#juP6Pi;Vm>Wle7JPR=KS5RF(Rn#ZEL|AfHgk}q_{ZW4a}7r%kWwe zrVy&f_hm00kL%B_UYC`;S-TAXzWk$t>Q&==*uQ+$Ofqj_-PyHY(c!&`F1ho;AXa(+ zTQle{>X%;(S|5FwCIEg(0;WV+S@yUnH570mJn)g_eU)n5q(KFLK?b_DhIdnwA5mF!ZfocB_mj#qPK z8**-Zj*AeJc0c36h5db;+$F6;lIY{BxX`(+7N?8odE~jk~Ls z$&W7OpU0IyaLN}<(rpK*)xOXVxOO657Vc=wfO^1`?^lf(*q+NO{rAcsXUxc|KPHzx zY{+IfI?4UVkAbz}CZkO4e_My=8Xm~{b4fP*P?n)wai?T8dYGk#du*0dKJlVPX1&RT z!vPIEUWvHfJeC4*H;P5A(k^7TwvqVDb3BR@=|OpYw&Kz*{Ug7vj&Wp-YlRw>rJ~1t zcJ%(t_9PSvxhXErFIXc;W953_8S;U6@tusp-gtk_He1#Dt&qmNcDd^}zT`62-W=Ge z6ZOxDkoDm4?^)ewsH)3PAT(_nUOxZHO$G$XXGpzer`|p&yBsj&nbP8E1Yq`3n=HIG z<@jWt>+}WrYT8O_nb3fLocyKUkur7u7qzCsVb?r|UaUII5vc{xMbj9X#XELk7{}6I zOZU3-Xoi@^2A}1(KX-CKn-4g4dwl{-t~A!RQ`vbi`Nb7hwFCCdL6%vDvP}bGDUwYQ z%|(0nhSHk-5P)Hq5vH-7JdnpkV{kA({Xqk!J|BGFIQmcVr|`GikEaWkLw>s? z?d`SH;6lBAZp=%D_^p4=ZTjZ>T8VAD<@ajqer2nUzx#iVAOHIk3Q&Um`OpFo*dGGz z1DUYErB;761SlT{f#<53g~_Od{gK7~cLfVGuUx!9+j|tc(C2=oaP`B065{6j0&Eye zX&W$vrtsOke$tTInWTYGu< zDc{w7{=9JBI%QPRfsnrPR)ez8+iM{1%4?1Qo*uCs=yvIs;cRWszi23N45#Qh|qrcL%Zj@{B%2$>IcsO#l^{viyQKgwa8va z?49?jiwz-stC9MDBXQQP*%6BPQ;FRFz7pbFAZ$^3oWc0%AK$d2aKBWyt)k#JTTXEw zBLu5ebmF5-(xXIsB7cWqIfvw#>lAAD6ue7)4eVu~`zRSnZF)3DU44qK+k9xr7EX~2 z?oIlv2M(GUh}sEQ>X-=^m{pd`j$J6(-4Wij`Mc|B7JB(xg6h$rcR5})YPq_YR`hka>K1O+PmT9kEKw}>R=NVGxrhGYpq|!h z)RMahvLB&_OEA`I?i{W`94Fq@BpJ&W8p6~E5a+`NOdXU?(tfW0OgWVAx|6WpX$yOl z0ZWfH5GKWX+f7*h|K~!%^0#@VRe?1 z7qMWOK)(r!-r4dio0%4u-y@*B1SXa}yBgg(nUnvJRPLM=S5aZw^|Fq0r^9L^>Nk-0 zUZ+Iu9#{N`%PwoZH*9eKEFs}b;K)Aq1BVw^zW;WQA%@dgXuqZvKzcen3tBI2GCXI1 zy3E9~fBZG;PXFq zp%Qw)ulnfTw{F#;GrDKI&SCc%QdD=ypyu4U9fsko_kBSygrHQRNcCsp~-^v6!-3V zd+w}2>oNW-eIX`2W*(qM`s>8Oahtf?#sBskY*4Z&abvHUEly&v{j{~H^$awsFbdZ9 z226oJFzZioPK|q;?h@aY}qAaxVjtAH4OyO|ibfyRBZ*geDYikWgO% zwech-NWbSB);Fzxv5Va7CBIq9-FFO!Ih@vXD~CG$fm`xGUfq1>rg6c1f`i&S{si9d z5T1dzbYpQK(@SEUMBg1ZBbMIg6E5!;DbopZqR#?3INkvV!2r8YK%Ss9c;C91`OTWgvMDANqzoaxT9W743CPsPrn z&X3?_lgh?(6}`F;Z;S*O`qWbnL49Q+mlx&|fpjzKE0v)7XVT<-`wNQRHsEX+Ox}h? zA_?mysY*bQ(}$VK)hyrlw!|tK{I$h3vsp#Y_NkUF1R#@Qw=ThXi3!ZykPt9A%OPUttKLf7?gxRW&Qwb7jfWx1IGdQx9VT%$-krL3l%`|+?PTPW%nz@Y5z1V9+7ER!?7 z8zOP-Q|A$43_pFstaFdARDXM;wL&$0N50nxN(DeIVyMg^=mSx?Jt`?lPEBhxQ#>S& z8MBuCXZL%6YV5e3Slr+pH2W#m?X@jYaO0ZnqUgb!OG~$Z@6Ik^*hnzp zxE81H>DI8vwdV1g+7Nx|j0v$J<{Ii5J=ei)0L~vUr;uUsoF7j;X zi5Z&nK{Z|gmId&*xOW%7KQ1E#R1Hm#){kQ@udL_4L1xv;RDLmF=F+0zQ~Q2x(i7GF z+N*qX8Z*OKi>8YqOzflAjP>KEt`DJofpJ4@@kZLe5Iifp3qQt#UB?zD@<3mfrfsd= zj@~&hu`>rzQ*STNd0j$@v9A_;Wnl>>Yr1kF%K!lU4%@TLNYYzXUD4V{1Bpn2(^IX^ zW+%>McH21sliVsbTYWa^g@*=3>0PE~lF+`#BUpLz9d!-zuxC7^!xix;L0yus zA1W+skc5*z^?(T+175acfiHDggS&6Au`Hv(Q*;jo0uC=E9b2GIm4e8i2H=;`u*gYo z7VaS+98IF+$?syGM2v}L;VPyC$;^@*KyiWxMZ&huPJ~R_*aR26WywjoP{W>eV@g{> zF(=hB%JW$QUPp%DCFq_)x0nDV@LwB4UqZ!SNO{t!WaJmw>yl|<6a|NdCnGX?<{8xt z@)d!2q`SMI;8TYj#LEOBH;%~^E=-X=>o@dO69a+wfUb9fL(CeebqlS^O4V9h_8Sm7 z``$#KX~=ic+sJY8iMiyp2jTh7?0A7Ou@v=VkIV5l#y~ahx$A=BK5mDfnEKk%EfPSW z(`}Ps>{vAA%6CFh56V_D?d3T!#k>;BNz=Z)BSU|yywZ1_n-;e`Sb{^QdC#Oh>}F_~ z$5>c-;tV~sOG+Mw8nSS9;zvw%#N#-W0`xrT+Oy|0BOI^YA5^utL@w@ZMtQ)*I?WoZ zBHli|u9AQIHPXO;d#qk9ujur40pe!QQkT<*aVT0AK9b3Yj`=*ga4JS3rUkZN1*$=zB!tPpdM{>nqp zi|=jmi2CD$|6}MZ1DbmKFnrcy)aZuMqenMvV|0ylATd(fNl2);jS*4~Bvo*P2ntAv z=pS`MP(VR25ET&+2?YhaUU~U)KA%s|InVFDf7exZ&G3< zK37znk5)IRpYS~T`An01jFxx(WWeC(>fZA)dWY*Dgns{A%ae~aJYD}V#_UV|?D<&J ztMyaKN57m~mOo_qsD4`Z_-ns^_0I3l*NV=ux?pDN@@j^zGZX<%8sc?CZ2L%UEVEME zV>*xMd16L4+iraSCK^?}xNodd{so1p005vX0LTGika%#RGucDg&|cTXTT)q9*$6ME zV=1X&s%lI?E8`UOtR>WqrM1kZux7$a`bzq?vf376s)iVxosC=I>*ZA$b;C2~n(aL) za|?@bN%fbD%f}1KbMi_8Ba@!KSOAMEn-DztWU$Tw5kt2}w5;6C9eo}@e<`4#Bc^6F z^K5?V$(*6R$JwS!v9zqE)wR97J)8Jyl253*Dak(hEWtY@ue8c-A0QSUe{Gn{uDigy z{{U-Fl2O&GX>7eSHt}|C(<@-CJsLRH*br|sb3wud7-T{BtAVp z?KtgN-u!A# zD?PnK!v*ElhRz{jakRFsK0Rw^JzMuec3os*+WFSYzM-*~d#-r|hF`kcpPE~2L@m!f zRna|g<8anVuh96Tj1rIFxTcP)u}4n4+x(E6#R^Z%lr-^DH?mXIwfOY;3$vKL_F-Gs zlB8$q4G73-;9S3a|MB6|uC=po{88qWzM)@#{utW20uT{7tck$LrAabk7}Ow zsTwJ&@3689k3HRUZE8UcXI0lb#tOb0)4O)8@rHq!Z`H+Xr#V+0(=QA^Ss9t%F!GE% zl2_@Sbw2Y{eJ-0Lrl@7^mvDb^JKeLlv~$cgrS$yZLv2cq{fWyuhuHY=OcnP;id&(h z*->$M3u9|PMaQT}hjU9CTOLkFsi{ndz}RE{LzL#Ha`qvr7H)I(SdJ?!Pdz z2x%F9M05?e3QlKJ9}{Cvnj1zr*e3~VS}FO2qlVEEmI067e~I^N@Gh>_2xPhS9k6=r z`0B@(y9>_;?>%WelsvoiZhdbrbDgdcYklnLV)XPO{oG>pLsn3NeD&g)-;>mWbaOdp zFV4!kzq+nSzKY>3lm4v%`2b_tCe7#FomxkZr8=7;_W%%5-ld1b%R`E3hm7|u(F@S3 zZs%Qko5xC|jT83mB`x<)V;qX*UHe)m&S3p6hwv>aKd8k;O`dn{Z<{)2k@kLJ!mp{k zz)An6jRiH%y~Xy7cIf0l$CFFs7Pp28S1Or#pzP~13$#hPisE@GxDR%|=#P7H+4GU;N~&Ny+g zw1>9JIQ+I#^e1we+~TO^yY}$rwGYpGqV6Au0FZdY&V<()RdwxKZ@78(O2L(kmV_ua#l672?qJ=tWPF*dY7 zCL*+n0P?V<-c=O-s=YnXc>*j|PEv6N0dt>!J_GYR`aqDfP|!&E5_rZ@X#ZY!7HqCU zZXtXgOos`tKTebw-moI+i+@yf+~z|6zyyFy;O&$eG2OS+U<~yYXK+PDcUpFlY=p+4 zjZ3b;+&M=^5ICgTDU?RqFOZn6#beR&IDzy6REod~S;>t}KqLG&XnnWb(IVRzHM-3> z*ec18aI92h+ewMvV|Q$tV2qhjR)*l9$92WGzCDjo|Lmd0hl_GmtM?b3z}9E+0E2o? z=)~n)qsgusdcQvNy*h*2iw5|$uw4vQEOONWCJm%;VX?F&2e=Q8%M=cYrn7E}(U0T_ zn^BTK!@OF1Od&SpMfkd)KaL^hp2u-q>vRX>`O+~*iUROlAxD|&yod~0g`~wBP#F^* zOx)qCwAF+CYxUnR?&`j$^dCk>jmoxLJOQvz4}Inb8%C=@HC_k(` zAu4n(RDh)HE^Psp{>SAVzov%7h!-K$dXa#KK6sBvM-sSzmI)6MjAkJI(V(M*Plfp5 zQ}_0uD}%0a4}oetMdK-yuJ#Ws{)&57!46cK7qn8`4xE{w6fg~KxV~C1!+V|N{{-UHBv{U!LL($yN1*%4yw*PR{&@@ ze7-dWi6u z0Z+6%QP@z2fUKnEq1pRisOYsbOXONUlQTs!NQh>2t0`K1S>Wy8cUnIt_8wXMiWC>8 z!Hp@KszDgK=q(q@t44aU>%y|k;6n&-yjPI=m5DK=(wz>Qvr#=+|0*D2Z@i|>nsHONlbQ)zr?KI$B;i-%ojEBT0Kma8Z;mXM?ZTLa>jBmw75 z9KiRw(n4jrwF__Jm0|K_ThSmIOTDfJik{~}{eLsSd!y7eFZSIie$GwNuK<7Q=4D#p zhwG}hcfIa=0vbkcSi|{1e-TQ`z;RzszN*cNbIcT=@jtC4S&sM8t=U>pG{dF~56(Bd z3}MHH!r2`jCni6Zv-!h!Zb}VVf9|degC9IC^5YJm=wj^Dv0KbVk zV6u|D>qbVj!u@S{o-Xmnd$1nLmpA( z!&$0E|B6i454=_UGo%)Jv)7-+Cw1#`nx^ctqV=ya7sSnf-6z+eaX7=!V5cO^nWBq? z;v=|wUp+OlaW9YleIPDGA*jBvaS?Spn%^>Ve=jxwna6)&XBGP@h)~r7!)47@y08Mc z*=^6&wP)P`%H2*Q9{3%_+UXLOeiHrDNBJiCs)7WgA)U?$T)$x=!2$RSdml77H*jK) zkH}T`j4DKb6(|fydUhoKo~{-yPG-so=r7Ia7SZ?+Y7ULz-ba0E_wN!Se#vYZmr?-tXez`~nK0k$i1zL!q!@PZ6CNNsnB+R^yQt zq>LDstCg?9SO`fz6(pA*#ZNsN<{5#wnq9mIA*d7r&;cY%~oX92cEcGdn!v|IZ_K33t}J9!9(P8{Bb~G=uEJ?OE>31xv%LZ}Z@`0iqVY)qG#FJ7B9hIf;~?)`yJ%8SF6eJR z>@Zt@RP~Sm#)P`$5XZ^2<-)gBz$P?lh@qd}Qu4wjsZ=n}8B{FZ!+cL(6j;5LmH|TaA-x1Yx^^3`X!jg4nX5t z$x*>a{rxXQfU)GlI1GGv9`TA49Lx2kXO-U}92Smc^`;hqk7Oe<0l^rsG!|X6L#@U0 zO<|zzY}M_@`j8|0(o~{_qB^b+)eC?*&Zbd&|U_5(I#o_l~Tzhq)=GuL~p#S5Cfo*0RAKwDuIT0z5}WCAfIbg@;`N|+si0zoktMpC#*-T zlX3Po5<#-!P(92^0Sq#9Mna1V?}tde8811Ev;(Vw?-i9(e#wSE<3AZA*v_psPCY&A zuQLfqv10k#X9T`UOU)VuLg{7|Y*N5c&76GoGk!?<%!A`kzyl&Btak4pFF$gnNMn{1wHG{Yq+ zlA&SZpa1|tnThm9BdR1CMJ1%v`c)r|@I_J}dBzaVcPNW&nmhsrzf38pIB$w;@XI{6 z?Rw!Hm;Snl`sq~Bb~TKKMuev~#xafE0nH;+DNR}UVUC8^Ps#nd22ZA?Ub%>8TDtnp z<>5%kL=1Mdxw^lK*zE=}esUP{%N`hvCO=~@QQN#VH_}|9{ zuD?T%M6ecPJ*QkQ^58iyU_l-^a8fPAYe{Q#&Cq$pGBzP;Dk~S^(0Aq_HSxNwz?~)ov%RTbdGuw)$7>r zj-!<=l{q>pN2AX?ZoO9!Qs38cpxGxap{U0#bh{`tKS3m|>Y@&#m2>mT2a)K@vYOe~ zIxO#989l4Lh*RS~(kXWYF`0vr59pk^DO1x^BdjQ4$;|@GVpTX3K?Ou2o3sUsy zuu--?+2T8Uw!4ntm?~@Fbv6RM#7~A^5^>Ra)g$;()*uTe;wBp3lwA-S9Df}JPQgK8 zqCIa4dN_rx>(NE*i&y@4bDv*+F-p59ZNMN+w%5hDJOa~Aal2a58t~q#FRFqjJjUNK z7c<395DyU82RYxy8&2&AY<;Pg*i*fF8|cR#JkNKCFErMt2Ja&YL3Qm2q-3l6$eyfZ zgOB%sv8q8-PCSmR{}T!;;X)q0C)y$ozutv~J@+x7NJT9r>vBuqgA%N{!<(Le*U_3B|uFk;2^78dI?!`;C#|Weqi19CRaejneQgM zh)uO?rwh){*cGPs))YX`OJs7R5JGrZ_5mx=ci@8@C<%Z|v0=a@C6s&8x|x#3fiW>4 zO`3hcQl+qXu;(7e_nX5ZcSl6%zLOn~TzC%syqo5p1)Vv_vZs~(K^Xl!kd_gF43vQ% zd;pCCz%ENrc^uS{3do@o4zLM)A^PcfxUw43os4f#y&=9OK02X0NapYViW_b-_cY-P zqXuTuXwQwW0)XQ+@(ppWz?&$5^q`aU0C@QRa0Quv;2=NzzQ;Z~B^p;HO&K<=n$Zou!@>haH$hfP>O}j|F z(me#KRDk@5JTQ;p=d0zFQ4ST%U5LFq{`3id71zvE07$7ugx3t}-i5NbDNkg@SsIJK&u9vxD9_&eXN6vYEqFVY6va#S?Ad* zMKa2H!o(^VBZvVX*OAV5Oi9=QFvsC>$)p~wzoTsRW%`v zp7@}W9`{&68x4udG!=Obwdz5}vgJSe``7qd82wZ-0mdCBf6bXzVHn`I~@)+uRb4HUWdTGogS^bjCr$ zK7jk8PJHZrZXYylLCsD2HLB+W*3bfnv*G5{O2&?Jf3<#cM0yuW)J|&SlYSRG8I$>Gk0Jp>-GYBr{*j#ZktWM$nWf|9Pk7u_Vt`KxoyI=Ws zAC#)ap>AR{vUm9JP!C>{le&rKD;T^wI5Rg^R@8##JM=&P@npfNy;}<{OE;S2*_t)3 zH%;L=qRtUJ(BZUOj$$Wyqi|yfY>E``w~SQ7d)J1u>N@O$QMIrye29wpNFdAm7$q#_ z06et~+->0-^haRoSpRMNq^dYtb=Eh_deN7t(d$~=tJxC<>NoiJxh=I%?P%%6 z;K^0i=bm-7oM{Oiv|R5$Y)(^cH05R((*5o2|5hSXMC;fKGl8|MR$`^#w^Ps71T{K& zq|gf4sEjVJwA{-cAy)l0RMq*F+&CFozl?j2o|WUM{2>ZJeMh^^2m zwA(0BywXQpG+f?b-`+ggt1aQ6BOAMUxldB%pqj_M&GvG!M^yeUjw5Nc3$~ni+xJ-t z2B9^Lw&5ydtoL>-elR9DD*Q~o$+_scYGxwz-T};xAS8ua83Y8-Mdqfjzu&t4?~yn7 zotF@(oQ&LV&P;jvYQFK9NxG>CS3%$y)bIJ$?&J2`iyuWQ+zRgTa}G*L;+mC!-LSc|KKoP5rmMy3<~3v`4uYKl8}PY$&@&qP!LOcz*O;&JdtfC! zAV*sWeCcH2GixLj&Rl{fQ&UaHYLOh13lreT8OT6r8IqP}OM^(^GIagY?8)e6zqFQC zuox!ISX`*Ty@$nay}(v2NJDz-2KjIX>^UGPLl?rc=g!*?V5XasDu`o;CHzo7aqOR?tAGJqXL@3v9G@s|QJgii0jjrh_O~ z)USxXZk_sD(7Gc97<XXr+CNdm|U~s!))yS63#d~xj(*h;R$9M7Z4prcf+b9UyB)`LF^5Y>^1a`|Jj#vuS zKNoRbS}m=NrGA{Vj8u)VA3 z3DC25MD>M$OEXe?h&x4e)4BH5*TeW(x}TT1=V+~usO3Y+iaF6up+xN)ch6l6-o=T9 zeQam#`>|9pV1T@Q#rjs=O^IS7Hy^N<<$3IwfYj2@?y037U7&#PyMRh@85a)y^6>yT2a#F)meEfhAXrus+0m8mX1}7V{QhZIxJ7dS zx=+#sB(}n7f-M?K8`C%=<<+xx#vAYIQ5z_J3{JOpYbs`GSmAj#y2pt`mf0iv9t0~i zv{A`uAjhc)0r$8B5G0OPTcmLoy=e)bALp=$BebXS_t8B~$ic-Sh8}-#&&ZhS;@YxJ zu3y@3q=aPA^eLmqOU5+As-8hQcCla{&?ipIYgLfin@lg8Z!)0Oxjz~3bvh*)B37_X z{o2#fRq7d%9q{YuLfZ2anTyA+z8CU4H*CrT67CxoeBWv*eWa-psA%LK-8*?>REGNB z@0C;G|9$@;wG;MdU8&BeWBFa6;<244j~v{_N9#PZ-gTW0|MT`)?YTcY*Pma={o&wy z`|l?aVZ!)Z=6}aC@lXvigFkwSdDakh2!GMrAovx7>~D+=o?${-C)2d&_tZXrD?a{u zSpt!~t|RWc$=dl)y-myDEt*{P_NnLWxKRkg-DM^}5~;!`emY>_vzb%U7mzUBWyvrs$)wGvEHSzzuahFF zaob17cq>xQU`WEMFQ)kDYLwFdemdi2XHW5c4sS01Ny2(zPkT@J1xmU~TEcxR&$LFX z`)NQ8)Pw;ddiFrpa=w*UzJSt@fY!N{JMH4GAbC1ZA@l`ighJp`JJzb6ob4X6W~6ta zCm*db+qQ9QONTR)kGopQ(D}KlB`Zxj?-hi!{Hu%z9ukM>_At!$l9vS9pRS-XetFUg z{La@U+|wNP;d56L1RiaW46Tk_KH8_<_$k`mct4SBz41hJ?BOM=OW^#S3VrVgjFjJJ z6XZB%0&>iF1C#3Cd>;pEa@xwfaFz)EV+C?#HuwG!AkD(<8ffU9HpxltkDVGha9TBce&L>X+E zReFz120cyZ2z5{G5jiaEeuiYVz?7Oh1_n5~8)e)%~FW)4w^NfLX zzBV~9p8$ZkDntZxWk$pns9g?49H`93NOn27f{$vtm(=DE;;wfr=wa;ls#|PF$V@%p zb0QKtJw9q+W$1TEoFi&7HmX_7IOUExEi-SCJl)AaCCSH%I&qy+LLu1vQ))2P8>Q}} zn8Hexes{MH0D%?7eUcXE^R%GD=31DJ7$`y=$B+a^Frcj%lu#T)?Q0ZsU$d&Yo(ht< z{2%hm3WiUm!?kzrioUFW7gD5sRvgb}4D*q|IdxO0Az$|?4GNF{qq2HdZ%^PB7tj-P z4HN433g@iIAma)Qj{8K|YN&J|hc=BrPLPsQlbVxcx|`uXd1WCC@B>?Q878gZ;$PkY z6OjKGvn8n5R}F~L%!r6AdQe5T3cj(|#lt{(aKSh(n#2?fW%olfdSg)LHDF|2q%Ko$ zX_yz$t02VQ&qtPx1!B|Ay-vC>_S(3r;0S-&sWyHO>2IRmps})CpOuUA`)W-mk(w$n zlhDac)Q+e#K868nc#?!tBPZAI-ETv6OM{+1b`=SZH&oiBLoA~6#OzkisH8JYJbKHT zbDkCKX}?40BKsuQqR@ofLC^nN%lK$_(HWqO9Alq4bCA^cq7>3E8YLN*+8@{d(UxFU1Ly8UHK8aGl#OFlw5DRor zyxZV&Rn6=P=RoP8q;bjic9v`6g5T}O}A5q}{q?}zEQy`2e z_t}p{0DLMEsyzN2A}-J1bFI{9J7Y92|Cg>0r<@m_%$URuaj)`oz)C4J#)(In$?*>o z1(7p#W&_gv=|4eN6EF=zTR*%;E<;<(-Y`CU><3)3>eB9aFC^rYWplPRnJ8IFfe|aNiUedaOVwr`RwexhL||`0V&9%q zryp25{o+>D=pL0V6_mzzcqdFc_{N|vwy8C}K2I>%Alvu~{)eLQ3$mne&YC&X{g~SE zAGh{STpbPCnC4r4NY}fgJ^AR1$|&piB^5jBqYh@YF*YJ8Ytl*7IyVFQxa(u>=og3} z>SZZV%2*3JmpFT2=S3+NY>zmON0t`H((`e?%~zxqrO&olt~5g|n@FEkZvAYxP2j>G zUc;_%MW1q!Aq2^!enAjd$CrR4;5>Vqn;<;?B!a>M58A?medZ;s5R~PKh-is!c7NLr zT=g%?@3DAgPO*j>QR_TWWdNGEghE(fJQP=P6$$FPf|BN9^Co4V$LV*kpdff=UdMoB z3vti<_+6x$p5+HtW)5I=-28ZCiS_8+FDf~@&$pR%#9N47~Qt2Ue=A3-W(Cwf)7(doIM_i@qfrL8; z??01Y{RalElb`@1hcQ6x5cFUX)E{W8E`qvKq}@ps`6aT7?Sik-m7YWY?cHtx6;i_~=3J7bd!AigFPJ(iypbm`eyjUE zL_r#IG!ZPgQG{;iYuPbkMKJ6wnCgCQ7qP5UrGOHRW$yz1C|X-T#<>jnc82aa_zvMJS{quiBkYXs{*+azenYTo zqp0ufb*&j61$vEOLt|EwaN-J!(hkY9y1#dj!Ejz;X=kx2<^8N0*dT68U=j2dhucF^ z-=|uKk82^~F5~k{WBC2aLu2Ar%3uD12etJD+s{kA%>$5-p%+)M7+RNc50N80t;b!I8N7k0h~MJ}j_ zHI;Y=n8`n)z##R&66evfzMy^V#b7+kEY8H4jg+sKMJ4;i^_k?@7O!Laeq`6Q&><#q zr`O|d&r$O#&oTrtjpp2%J=+`AzE>bdY`5Nal^ZiCmE{Q-mWTTkmy@=TCi1g(bp97Ya zz8_R-dje=I|4%UT3V8)o&c?*9_@zc*;U!w#C~2oi-R>vaUM1R#k=7TNb%mm8Uc#+( zqm1pMOuVA@Ov9qgQr?J=93bQ8ZTnP0;trgOcwmH+%eR7>dMq0p&5;Yta^q(Kc=Dkhz$c8niMQ zYC?<&{9YXWUBO`R-D34x%yg{Rivr($*-j2aj2G+O^w#_6yTE@z$zJQwW!T{`RoZRT z_icxa#zUehv35+Bjc%waMnu&jBInP6sv8#>`41=4UkevuJVd#@_tyDFw}wazJ_v60tNSK_wR zafdz@Mn+MRT)L-kTs0H8G@c*AR;<7z_JdGxJZHEd*6}ykaIEv5x zcht`w$)BqMDHj!lV76VdFuwHSr;RL^p?n|Q{wr=?vg2R&s{fzjyFSc{-p9l53fNNP z)tt423h9l`qs1+gtZ||DgvP`ExeR~uC-6yzZ60+0FgsAhGTnh5pe5TXybq;l&U(TA zIK@WRpzkhj*L+|15}`E&?n)Kzg6>xxuR#fhYhJ?AHa_n9>&sq3C!gEheQK7dq?x<} zr-#%f11_+NAyyn26_*9`7dq0SxS?3N3%o%E!BhU%tyWVLpLKgp%qwXRcYD`Oxmr=v zAM$2bVSV>M4pi*WjV`Yp>RTzi~zVgVTP@1VT#!M-}=1p3W*37++9{9_F zC%?4~!CW)fgp~4yPJ$fv>9Ivn?;)rRa@Tzx7LR=&hsh7IN5s3N@}@sYH@;mqTekU^ zda~ww{Qc;-lbb%mDn5_Co7ktw)*SUV$nX+LwYij`7=DRx`=i5J5>YWh>rz29f-Za- z{%mgF*bL3NpNV~A96t|BKbax!{o_a&oBQvpvC>xZkJJ*yt-X8kdq*@=Qcu6VQ;?N! z@X_S6Otja6ekZ+@cW>IuzX?$N%Pk6ZeZ*TU~|8BfF zv?QFntdzTAko(p?chx&r2cG-paPIoa+>O(@p6TU_oZJt0a_$l|(Uha45h9&E9@9)zaGx{@p=2h4}&FytZ<0h!Ys{gR8C?~X>ELH zdlpI8^y^OgmFhZ?53xu`>= zg%TcfO9g2yv!jxw-}}E~cb}Ms@X(HY$gLau6Jr~35K-XQ@*$rSGHSarfLYagAnBWO z!G&CYB9|Z|NFmkbOAC%46p$YB8A%o)MRxF~mu3(GH!3R||)kf{R?n~fY#ciQZgv_j{WjdUV$Y?w|$kLcwqwtxPn zJz~{YYzv-u?S&pP8$iS1em}_^F+mI_1%fw;7*UFXn={}=GjJYy%CG_u{gR2sCclIJhi1pA^)go$g+ z^bEXC&cff|vnP_qX;^@3rr^ysB%I2K2Jo`6dH;hTkCFa&Us5MTji-yk^|*Cs(CNS@ zSgfVIUKzmsqZDKlsWdZXy*HddG(LjtOU#`iD1{CfQU|UR!nNi-v%wA-T9SXZe+4>ZXAt#K1We*;b4G&kxMUH zMl*1?D1gh^1AKQs>g(|q&QGd><)fJcNy$S1&ev( z4PTo^2xyan|62w2U2~kvenk!2fu{f!lO~AN4AFDdk11inIO{j$Jr50_o8QBT0DA+( z;0AanA|5Yv?IjrQ>BK6k^28lvhj;4I>CKB(MIdyoSRl0*76)oKwrz5Z7stcM|CeoMSYbt8)n$pwJ&x#i$JLWWEXwZe1$@Sl544Odsw)ckuo1M?L)+dJv&Q zGkOoFiePm?*vjP^u!U}ae`l=`akt2M1AXoLErZ;vX&08LwIsF3irkdw+n^t;^0U7_ zC3W4cetlM$DPfDNuqgmz(9dro=1TJkZX{uic$;(hv07S=4E$XsMk zc{F_KJQU(&8GzRCB$M~c`(ig|q&AHk1r-z>jc?AX5z=)O^fq1nZa%KLZPI4kwdt8A z`vlVS;FA5+W%6mOr<`tdho@e`Ub6VpR>cfw|JUz*F9kmvyuH7%W}6uJ?(FkRgBd!W z4Id6Z`2BPMe)Q6ruG-{&tNA2upp8oPc1+*oKI@>awCm+xFzy(?=$t4llE zi8_s`!`xiM-pT%=(JLFaMOy2WJoQLbFFmXTxnyB)HA8PIdWLP5J|Oes@-3r}7gTS( zZ&%^+2Y+FDZH%s|tdBqSj7;h|cx%g8lvr|C|2yUG%?HSYmybU_-s-9C( z;YNuOw5b2{s!*|V=n`}%!~Sn+9SC&>`%fjvc`QI$U#$N0UrmD_88=||qI-7}8^2WV zWnXYO{d2ZubwzH1L<(-o1Ul`$brp_(h~fSYj z>Dw*(RuB`+1gl{&fDH$xP5d4|sy+<<@AZf}iD}Y#4hg2~EG_Dgn9~=*s2nD`?t)Y6 z2w&xhehBAiX@mdxYtZ+lAo9oxhz`@H{ue>j*l9o;LAECrA;dlCDgz8tQFaoKAh~e# z*_fR&@Yd^w--JBRsB9?{=|wcDqJ~3XuWv6k2`;|$tQ5Z2mpCx@%rH0(&n{@*qmbhN>OEt9Kmo>DtH+VHA-wqSmT3LJ(fJ z43UE`0wYcGjQiM)J1AY@T)5Q_I|S?hq} zV^xVCS*FoY^xUH4oZ^3>M1zF}XxPYq1eOYA_4RI(V+hgmX}H?B;-85{(U&bIYEl0j z@9OwB+vGw_=U2>2nfAW<#_)3wB*K72C_zKbyIWeyOPQ>{qPRkJ{2T2w@M?QkQLPl? z6B+HhvV1c?+7G3whzj?!8}pimF2$&a(qg>Bf+4!Aj>lVk+QZ0`jby7ZiL+yY|K4im zs)t05HNf7)%!327VnWv5J-Y!{8<6)zwK^|d3=?X5%J5ILcW>UClC4y zP8_D2L)FZDTM|vy4%)Rv%@I}VRH#{d1n7K>d7#ErMSiT2(xGk*pDc~I$kl@!b>J^E zZjK3g!Ay$9;ApScU>a`d)rA1nXYm?9*xH-kwTn`Pn^ET?~wk(yBW9!g&T_TQyRBabp{LN{-D?OJZh(MNC=Az<9N4}EPDbiOwO7QV8PIPEctA6hC4Gpb$=|bCqyXJV3 z!*bgc^I_Dito$F34O}@F@6O>yCfK--?7G~4YMB=3Dm8?~# z!N^1mhpr|coWeoK)9|vrLV~(8H*&Z9>oy!0AVB8_^8pBnn>djInqU@ut)e3>yyPVO zgaNS@4i{Dh8cuqAp!a|*2{iV;D!`PkHUO%ol+LyRw<#d;tz!2sZ=w0qFY$t?uTNy2 z0;G^_QRoOXjsd37Csw)a^nybh_`Rnnu@Ektf(CjLh@1Co$y;eO0LQ>9Sg;R0eo3an>Dr7^bH+u9)J&)-_orS`QNJcUnw_mh6}E(`jYW<9wv5LX`N(Gm@7C zdavj?{Mn#@>maInHkU5C!+MpBA`DTk8DOS-g3W>pKfNkk5dV ziUfCnuU>V)ee?i}7wE}NWZ>mW8EPD_IKn5;E4{C&z=!FnPb?ty1%SNj`Lq2hBBT;= zoN(oJ$*DnSsdPeeC=?B?JU^KHN;`r20tuGhQW_A<@Vz3tg%`mxK9=uQrd9dwJ107* zOpqE~%(z%62=Mvktvk=)8+{%kx%xME_f5hwR{W6^*Teer!?>!cv|*oFn$sH-$uW+g zBjyT3zN}TiSM$^armI}owfN?KjxfNJ3DFI|A@*eCsY(xl?$6MB?Jj>}y63Mnu%JgF z5yWlkU^L$6K+@=nh!B;s)u+vGB8i4d!IQX*1-#^jz%47T+|Ir1`VpOLg_5vG@4A^< zl-(Ytp@EW>eE&>;DPw&_RHg)e0IPIQEy(f--sDflV z>M}*I7a@-DE)Vj;e$7lgMM!q?rK8~jJJaP9u6UyOvEx@EAyv};j2J?KLFNGIX`cP? zUF)Bay?xb++?Rn#0-_VoU&?zSK<;PHjJE>rQvMLoVa@7k`9Jhg0Uk---FlWW8%>wM z228IdS@`(bWgCz6Tt2yzzBfb@hcdHA`5`4@FNE&F>AWw4^aIBPgwr?6aCE-T?ypYx zK`eKH(vtH)gjXY^XoF2_a*;_Z8&nq)fM1usE^i|jc6LlebYeL*|3iXZTv zG$5vsPQG?Eb)K7;3|4ME4B9%A^2x}##Q;tJF8*^qBvMLJjdv?Hz1R`2@Q?>Nft2wTjH}@Bnd`YpJIrp3igN64rMbH=>R8z4nNapO((2j)XREAc%7!UK*(;WksC|$&b}8b5#@t zY(g>tsrMyi+l%R6*D6UHMS()fpImq+e#V2U$$u04`D}iGnaMYG53)a0`W1Gv1a#wzog{s@QwP*k#~2h>*YqN!ta`XCl6e*x;kUoDEPZM zf4^BNrAjZQFDkp&F!JV{L5X5SbE;uyo5E!Uhqc)8_B~eLVfwA<1t< zEa;)s-`7iNG33ui_Rne<)33$4hFUpXVQC?D|k zSL&UMCcd@eN3+BSyuxc&OfDslv+kSQ(EqvY-?o|^@8BDIc+=#a!IZW06nDLZ0)R7( z%Cx;juq?z_ZZO2bM8wvMf5G?G*v1)n;WMt{OT%Jw@Bh)+m}G?{bHx$rN0%U%a|EAr z0ou71hcVLc{)k0(?@C%jbg2LBXG{zCUebGU$7W-E-_vT>E`8&1z2Mzor|;(uBmN8f zT>l}@;=^#0+-;(Q@uYz|Nr>Y=rA%|5;zmeK-P@P_e@*=NFp}$$g z&hK|p*1nTMUnBv`NzCNk4?PkNZ_Kqbw_RAyvV)<3+sYY0Jqbw@%;XT#jr)mgoB$!^ ztOt@%O_l}xsMxeU4Jiu>)~-@JnJ3u3Ldkn5?ibHF#~Q7$NA=Lp8_ItDd?1Ro^WqJc zm7hm(FajT7vA6~#VdpEHf$oGnt#1#XsN!#N-PwXEFa_4!UrG+9>?$sEC@iajsP~=M zR8F=>Dcq8->Q)98k8aKJ+jXC8Zgw;&oaft88b|uC#yKv(vMrU9QS0nP(RT}K6)Z0O z6^aX8YO<@+O;6cx~?$0Va?GzRiTVhSBe;N`bJLa{&LUQ?qb_~kN(MFRlIq+nRH0a zZ@IeSwCKis?N{7)!JNj(2`InsA$I2={CfK~GC!z1?$-W8h44oPw&Q_GuFXc*SJ>`h zT#NJeD?7MS=B7DjPw&BOF`t`<1s#*K3|iUCG??AL0jVt0oJ+OPUYCQZ5?qe8k0!40 z=+$vY;FP_lS#@P(u06}(v$A>B@xPkVLXtsnJ-=xX0fku4eW?2~SL;OSYe_cg+ZWqV z7g}{d`fdWxyJO+KL+oFq1zoqyZBewK=5tlw*&z&`0nIo?)sOTb_4$X&@8McXdRYhk z@-lNr%dSo){HyM2u5A;mNfxtX$CfWAr_dwYU8-GVa8?^n)~pq`x9WBi(qnmIwfuB? z09oLzFnPaBOM%ZOcRbC|UHIhBzvpYt4j&#Pox2Fp_P4ap#R=Z&br_^vg9NC9 zMP49t3|6+ek~b_Q{zK;Cj{({kjD_+83JBFkLlZVE}iBG|b!zchC>KthE|YMPcr*gntOg=-ojT$CSSkedlFk^a53qV#`H`2C8nhEq^npBWaK2w7rexIYaSf9LNA3l z1e@~KE-72q}yF_?dyL02ZV|rrvTrk4n3=V zJf$PQ9sIq;{nYyalyG4LbgB=Cj?jfhdy@Mrs0AvDA#zHHCZARA#(Ql5+f$$Qj}Lp} zt}E-)LGUhiNY_QbY`=;WPv6B;%~-!#g;^i>h42L7k$+vf;q1>c{(k54U+r>PIwrQ9 z`7yY;sv3z3clReYji}x`uP#aOev@5JJA%$=x5Riq?1-njTUont7jU@18N&}uvUCSD zTuu?ET1Hm00Xma|2!6_c=f?AoAcTevOoJx71C#; zvU^F%z7T$L>gKuUhZi_w^CJrfZ>k0#7KZ&*g&See(>ic{gwSfRGNj%3d#6N7st0yh ze}b)IFZpxI<7{Z)9e#cm)fA;y!e@o%&yo-E6BFxFsR=@M&wJui{{%WI58bNZjM23W zU)^R&9R94Gi@!*EjPAt&`8l(NgKH8+LI=AC=gq_~ zx^Sl=tstKK`H$qPNKa4atqEM$IQ-gXmwv6_g<$W&xYC(Z56^gf9bWAexR+*yegB@F zu;!w=pI+za!VE(Eq_&w}=)HV?kP_1d`D%XIo& zm3yl}$n%%AV8ePwt z5jV%X*@lgnCcDn-f7--ekno5M6v=an55RrX&84$nkOQNeopVGppHCMZPC%mpBB%5O zMtc^I?Zi0p%uZ0w?oA*M=y3BzEX0TUojrw~QPKn5O|43A{}To2d{WOEx{nultq$UK z009XbWb6vC5nkB93(S%hV<;p8cOsW;REDf85n>%30QR^>(i;S)VD} zcr5-eO;%ArwuHyL(yk~cw&ixNqGKwKMSJqMpa_l*4mJmxwKhvySnz@OlBD)(rvoZi;$Au`&1Q(xFnZrr*Pxr0|6TB zo+|iq`;oRkSF;)y7{s|#%xX+O=6XvjA8_i;cGv}IP z)hD5%7_2J{gfE?PE*fz}U^e6SLa8tYz*bCa%myIfQg}F>RgnNuB`~QMxBwdPfC?Hs z&uLT&;XmNCK(+lBj(Clv?bEr~dxW|2S%N5NuM1o&3{HI%YwSsZaVO3w9M|+B*FOE} zeF9f^$s5%ra5D8vhd*qKfVlOD*TjYIT1>BK@q6{f4`|XeW@l+D`0+>j2QY-2+3zAU z%q2SfNCed(I@Kps=kk(TDkfpi`J`0nWgomw_1TV#_;w%fQx}QAxov%v1QT`4LKM>K zsQtc#nP{K;=zD62KKLxt684R>k(q+Obt-+sP~C$rka* zsm01wxz=!D#2a`NoBFE>vGR%Sic*uuk1~adGKDeMa(e~wLx0ixWypI(A`xav2flo)I(+v!&P`kJiiQ)f{-(SH0x#iw1#3z`>8i2*#K3uIWk>>*9RPo^ z0|`?rmvi)zdG$CS0Ket6GkA@!wTT>ow2Cg4n_S;F73;anRPnalxLj9SD0RH<7n;tFC$KMj=0jb#ujHI^L z@jCJnm6az9{+h~nhsdqDB0pRL^(Y4uaU24KhM_Wne!y^)7i_-G$pd`-=*}5{2N{R* zH(zA&qFF8R2U_LeeB8t<2UPPIteRA)GltWhT4~B)z1m~+_S?x+3{;rFMWnFp&^^w( zD)_Gm^-_U;`iX6wU!fC}6~c*|#d+memXxCaEsrpzFWBQJ5#b7UW5P&{2YfEy$c(6E z^uR~O)g;4JCWLw@j^&fafL3skHwpN#*?`9$pdDOf7%1YxsjSM%s1H_}_F)qBLt)z! zMka1X%#aTCO&-1vWg7EGCr^5){(2xCF;v2HGfHAOjqeF)pCrbh#j5;>-Sn5R9F+aH zrZTf~;iz{ZRt)#D(`{$;m5YJ@T1w~rg==Q<~u-o|> z=Jn*7B4l8yVtLjtEhy&Un-Aq2k1DP^asFGXE%~Kia)ncC?RB_korT4KbkyU6{l2-L zW=Dr9fHd&8qhmw;Eubp3JbD%4bG>1{TTv0+n19Sid>pMfGv`DL-F(qfI8q2|H;ja< zJiOPdv{P+R^VWrGX4u=mE!>Trtt3f(4xgM=QC0YOfN^L903qdq&a!#&n=aSCs_0!K zGJso&T0+fu3mT>4A>+ne+B`gNU?2hvWNB#j#r_IQn9|`vg<#M2x`fku%82B_2n9;}63tTU|JZdjy|ux6ZZ{ zkqxwJ^QFQW=Y?+h<)*sCPXAQd1)r`H+rle8G#UFFj>6cvg=Pcio1o4|8(ckEb+?PQ zJ2qoGlJbWhBt!asjM9u`ha5-lB9IhNpEE-6d&*eTjd}2i#YPT6)q;j7qjqU!db{G{ zU!~^4&YK5y<4>QCZ$H)et0+QUSTEmSC;p+9vtJ8~xT9@6%=&av#kjVW)Wc*=g;mT= z4{{0_-@bFh@tzfFNL}e3|9Om*@8oHNstDm{jfEnYMQ876%<3VZwU8Qe|IYB2Nb!HU zA7ebT>4cG}uWG$LU3WU|<(~&OIdjAH^Id=EZi>#0`7YEv!-CNB6MvhFqLpF%Wp%6h;|7Byfxsq&r!}ec4nE{&+l}EfXG^) znAD*Yg1Zqu%gvhlX+;Omu}4K((pkL*J2Sgk?-S666&&Rd7CiA=+XvP-XP8XSA^RuR zOBBwJADeo_p5`bn%b5_k$p&}^Td*@SbPbhT0{+v3=%AqN3ET@&f}CJSKXoAu02)OF z|A+gy^9jiWIMhoPW<+=0&g^1_)=@O1y2|T{q^eF=TQh*4W?iA8>4oO zKw(jwy-h>9GwP1fWz^UhtxUp?E{Ez!W6xSspS91OPuV+3ne>8mh(@-`3-+Q~p7dwOp zGwL)=f zLu^m!Ukr(Cjec`(*M8r4`Mc*b*7Mr8tMyCAX>2on#I&JPZe8%&2Zmf056vX~x*X`Ws3$lkrqe}>b{?`x6mDFTY^lrX+SYN_Y zjm8Y@Ej2sTnHCui?yq*99=pV8G<2{z5b^X*kgC<1=Rr(mou$e|opX z>~hpc#-BgT$Ezt1O7$34J6Bn+kq++7oUvNq41JOI+sW3SnI&*$M1m+BHS6yM_BrxT zk-Wd^n<*g%>|Fe$le?WzIS79R(!4+7m!tb4x5)*oJB!K}PnUmDjJ%3zEMehMmyG8| z%VHs@!WJAj+h9}}>QF0iodCP-^|G?dMZu@C&pWTKO1q&lur|EA-9^GUf4T~KPP%uA z-yg$P2Jv_HFTD!oAwUF{K=*;X#M;ErG@95Bj#I$4rWVu;iiV{r+XC$b#f?#6(NNzo zg%%$*ln#KeloiSifS3Mw&J;2*@Bbs&sBKAdgl^`cBz~tLbC3@ctn$w z!AMwJ#)YztWfn)iUKbARUU0LG0wIPhQifBvU~(KYRml9w{{ScySeX3?LfoF1gnTlO z5k)v2u;aM(oeznePB_fuooU!oH`FwZ($1Gq{VTj$)RC}(G~0-lf$R!wO^I@g3a+D! zBkKie?!NQEQ@8mkQ{u<^b3tL==mqG#d_3KPqi9h`lg8gnoMachumt9H_NCj=3_NWj zq0+zAr@+&a9PumvsSse(kN7*lR+?ZSa!ApunFRN3ZJm@w#UConh$uXdW)TL|Em(8x zGXr?}am|O2!t4YxSL#)I24Av1C-yogVrP>3y0S9~E)LLH*7NrGgV*93v9p*S^El9C z^1;LU8)+K!HYpkPx6N<4yfEF&r5HT+P`1G6g8`UOU$uVAx@z&>>t;P~;{L6S?pw(= zHUu1+%Kb9x&Sk-qe;EHN>9-HG9<>_HaK)(~M=oZ`q8vhmW2{9K@?AHd&z^ejn^bS{ z_P3i324)?%-Y>FNWb+j3er>VmqyykqmOzo`e1;UT9AWOPye;USzH{c)>vYunSV4f` zNfxIN{LYUYmjxE}M%pn1i__+?u|e__jeg8xGl%_VWFGe?k-WqV7=Xc_pxHuFLh*b8 zlnj;VZLkkolv8*XX20Z*%Ce;ko?$U1Zqp$mXz;TygCGRJfD=Y=LObA07On|TkIcz> zjAm|M42X-1Va^nlj)sULoX+uwP9Q(Z8YcST3&TXo;?BLjBZrGQeDan8j&zVl3nw7% zOy=DoL%GlOacGN9v1uP>@DV|mn=CT;gnz<#0UD>3JQ>`OL=t&jqV}s};{GxY#(S_( zP@rUiL{N{dA4ErxmHcpm114Bu>z{ng!o5 z!4``FwcrjjDv^2Ym(j<hz((s&z9G@A?B};f9 zZ0US0eGK;`5?Ii9<48oD4?Qmd@LnBk3q=EE|rXz=# zM3A(vHk2iOlHU)LBPWeV7UN1mJjrf?p`Zdl-wW(a1+fsY$iQeiN@--os1kg^KRQ#K z(0k8jTm8C5Gw;`1s}RI9BKy!n2Hwdz_faXGmG3#3Q}~!3iCOlMpX9aNB4!p<9RGKt zCsdP(U>0Rkm?dEnCamib^idh5JTBn+P3AgZ=R7MkLKMyp8b;7@mDqdWEj}RY#RTRe zo4QiP_okEj1iga2V{(0kA&1Gt`zY;@cy>K=A}^fM6Zt9`tNsc;+b>jTn^yJ z5^R_FHOZkER}p7?^xI#rR9>x zKY$*d42>>|b`{Pqc%OCS`$PPPzM;F~-znRv-#UBPGcWx1;r69* zsQ(8@&LSgkOUXC00OlSqi{P6!KeELKhaUdUmORT*miXd|sIv)S7n{g+%VQuRpPO?O z@pqfM;L(0a{@ZR1WJN{+vgep5^;$&{1z$e0Y&t|isJ@sR-1f6B0>BtojPk6qcGdN7oBw69JsSY0a8g#szG z%oGQr%Vu=WLS(F}l{B0~kT@$d0DL;rbhpoZ;%%Bpw6`icNY65ks+Z8b3(CQjfmP_jMsA8T0{{zGNJ2RTZ=0n41}ZiUYiR@< zuDW=t#|659vIz<3;gIbRxK(_*;A~DT1;aQ?8HB0=W+_m;71y9kPco#xSO_95 zd*L8fS?|+eCNEZ&b*2BDr6*o+g~ciQloBJfkUx(+XI7t(r}x(D%zjw&iQ2wa8S zg#!ISa1kn4i0;%L>J}0WO8F_yfwT()oD28Bo&10z1!r-1O83~QZKcQK&uU7|oxSOw zfOdaS3Q`M7{B8phVR3o_juh1?xE2SQ3HE#JlJk~NcK@@3MV!Z@DGjZAFlUUu`LwUn zhVN58xB$*mObW$eQ<7h8-0r3IV%A4EI_bh}nTj2c)3+4Ya~AH60RaqqMI0`r>`IKe zrsd+5XdE21rpRXlj;BIfP^{ip&Kgp$Ts_Bnq4%_N8|00q*(qlj%ozfgGG`&e8g`tL zOPT(@Za!O(ih|fH(Nc=)xbkQUOyAo-lb~wbUp{dKMwDbZCV<8YvGO;wBoM3GuE2yD z_B4D&b15vYqJl6AGO4MIp@GAlS@UA6A6Oi75RD0ZHPB3$PL?!`0wpUbILG>0Lr#YS zW?H?~{S^vWg8xzrNG~Ii+J2=tulnSo`#@gBHFGQSMHBA_Ra!NGz@qk5?Ru^!wM`nV zA{fQGUuNCOS|^U6PBjU-eBhy)D_WFFA{bU;=VE`QJlO@-pUm=Sr))Q@!NgS_(g={> zNVO)263QC>wwR=QVtlm%*cwe_pVS<-U%Q5NrLf2xjB2FM=$(o!M0|}dlVm#5r*v;m zUQ1usZYoNfiGvlqL{;8opER{iS8Mm@rOmj19BUd;sTBcdc9!Q2Fv?R#7jfh&o z?@!zaNV}cujU82uO_0bFWf&k_++(uQ%Ut@`JDNtmEHd8&y=DJ7xxs0_xnmIXZX)Ep zi}Kee9Xi1;4&ka?>wn2&kAB}+4e!#{?A+WUm`-+C z_jlIKNxl#^&ELHq8fOvv4)g5y_2(&8$@zwgHAYCH-G*yx7QQR*R?Bcq&-z@?KX$P# z_Fm9yRn;x(tqh^PHz?&tctdF2HycWBiss;A zzQp!*_Vx6Ii=2GbqcqZw`0Xm76|EsDvqv1g$&7vNn$kAQFA}LJ<_O+hWpn zUKb<;jKnB;XV{8)n`-8c6jc?^$={vLId#hR8gge!-e@NNU<_Y4^D@RxNF7%0PA5}+ zM66)z(u%j9KvL)`D0Qg660B5^rC1l{RL9yOGnypj>Way)*#jT~V`3P&I7YHFj-~Mr zu&$jdkGy&`a!a2Me!#)nTX#l(gqg-TiV@3*i>vK%PQm>AjoF%*NfdW(QojI^YobPCGph2t2I6Yuq-WyhwLkfQgB6)X6Ap^_>Z4 zNfWK*itfGrv`@^Q`bF}ZmGBbZ*rLcdfUxUtObO>OYSi;x>VBoXOPe28miEn`0++RV zu-{fTxp8IZ2ITyciSR{(=R%ubI?`BpBP>=YJbIo66EzoH#`21Q((c1L04(sy*@(01lyVIS5ntKcHU)}yc+Z@o8&MH^4U`EyJ*>?Stii+D=JHu9V{ z)s!}0#B5To$~{cssd?Dmxi56zP^ZFai;le!{cqDMUD9!Tvv;nn%Wtc%YqtnuH|2haIt#I}-Lp5Eh>yZ86m*f`Gu=kvLu z=bKJzYhBNuUw!gyT!8UUq*vv|i}Q*HO{~5 z$N#x&Yyax{_pX<3&acVO6$ql3xw8*nEQIs1-r0omlz4^n{QM`?UBqBJvHehmA@oT0 z!_+pbXE_=V9`QsWOm`%e1j*G;$T z<}45(CiMn|6*x(OCXGGiKNwSwu8_Uurr=$uCAY%C?-j7mI7kSUbS?RsTbV_A{3j#F}e z4|jN-x1x2L=&Hkb#nlXCV8EsySx)o8m-$)ddB6#fg8oU|ggeXA|8y;SCw+fH<}3q# z2iUMZoqOC6UcG{oRyV&K#PX)X?%Ip@A;5tHA)rn5Fu+NNOdrA#g7;#yLi~Nf7X87}3Q}HP@p9H&a46R1?zg_PtFG=RSPR^`(xOz{z;f#T z*r9i)0(HA8SPCd9sUN${U?>uVm1^Ze5j4P?MngkTlD!VB#AI%ajR^hk>QC4~C`|4! znY0HTgW8hxH8RjKxgN0yAf~e-gr%3&f*!8N7pu(;5+Cq5vk+8-#mhT`XpD2`c3J+O|x_sll?wb=SU9#qUn0klP!_TAlMR zrfb|kyKUV)UhMaw0+Zfjy#?!|ESf;w70Y=+ND8G04>3Q^!tr>j5)ve89~T+xmfp%9{^!9wG|0Q{sl@8wu`dNc_J6_XFo1RY{y3(z*N zG4}3~wksMK9#K*1W=64qG9gHQkj{R5@(s-Q{0I4bfi!(gnPrGGU|5VB>HBHJlLJeY z#z;OP$LA;^5=?W%{eH*ouXdfCY4H1#Q0o;Zh@R792Na?m8A7fB4mnH>IZb5ZA@6h* zP6@#`M|smqk|Q`qxoTX#R$3b!50x;Y zaL6j_`%ei=htdFnJFfI%9-r4uxspe16Hw8k>PB4-mPi_$Z_at21#*H)V?~hVp~^+> zO@XBu`PK4XY`IKRZWS{~IThZIb=Cw_ppeAVH<+WF2L$3UXF4 z8u;#IB-SR$#-DJ$q6^9{wz`gl$7Gt_D^Jt%jhT@d_PzMnO0N}G8C2!iS|8oSicK9a zSTLws`Pv;1kv`6wR18TviEc>ji;)!02)Hre_Z_r;c-4(W{FGk4nt=83fTdzz=!2k< z$S+Nor7n%UDg}uT7P2F4hl8umW*`5!L+-bqp*UZsA#`SWyrk+<1x8+6OJ{MHZ-f{( zb6oB6{jyO>Bn2QXtK{_A82Dya`al6#uFhaNG2Br$Z9j2W}?t2avh2s`2oo zi6P(}(YSLPWQ)u|Sx3g5gdfjwnazCC2fH~}`f|AvcrBz9F&x9R*v5Mc5g!V~PMgR=fZVe1c-Q2?Ok{>$z>CzTCqRt8VW!aeLqTd z6!OeR)1m63WVb-V1TqSzqItlj59FHPE(5Y1?IodsUJerN$V~o?x0jsYrN!qikCsLZp6)7gl5tX`)zM`wpkY^tTdgAeN+Ia zl9^&8_Tohd_sSujH)s}$eP+(*>pXMokf?UcUL0JDgmWIzVc!t*Xv>XEHuqUp!(Kd# z06qg!jzx-6mND$PtOsn-cJ=@oX-@~~#!=&B%t4-<6B$MMornbx5xb?CiA1jCYh{JA zMBBiOHe|cjrOD=SJfPT&X;Sk6oy1E&;yRvwT2jvb-KRheeQCNTZ5dpdTUq*|WG-P8 zX|Eb!z4wU39eS7xvLt4vSo`Zn2Gf%WK(?&(G%G&$3U^X-w)Fr2M@K7S_u0#38B84b z*zfj5mN!e<)*mJ9Ji)y}2dTmsEVaHMncYPQ3qjts*Z>c={pIp8VSVgz-%f#K6RSG0 zEP6nZbk<-8!ZOfj?<7LuZN+82CViniH=1;FV&rnmHsA3bp#xs$;F>}CKw=CT8-8dE z@10t2rU8h5xINGvHv?daB| zOHSjW^h;KayCn1SXaraqP$@5P@L)Z-0qxq8j!}tEzt+)iRgu(cUoyb_r6B#DQtW zMQOb`ti97;Vy-1+c~GAaK(3o`xZ9hlt4%=O6@c0{UM2B`p5QtSIGlYxnQ7;`&Fk*7HtLN;G{RLgix5BJw~^fo-%%KiqUX!@X5ErTEpq21O@s7am{!gr zS#2E~lh2ztU4Z7LqKib8)#bC^(i+@;LSPHgw^eg?kzXG$!_b%wl#VS8Xa5rd_exWn zOv5~r94+AgzO!!ZwE;n~(aEZvM2-zYW2lgMD$hV^6L?QaoXAr&Pbh78^X#?U$Qzet zBB?D-IVTb{DZt)`R_`1w+Bv7iB}+VQP-u-De(*2|vupw*((=3>&#l?yKu`1~-wO6~ z6>M|B;`NCvGQflc-1N{)R1(6Y{~P&%40^FheYk%mY0v7hAEX>(B^-nI_~n|rVz!3S z7o7}d%X=WR7|a&b(9V4XC|Q-}fKFE{upcc72-;#1wm%u1M>t94g`*%26%fi~j8$b; z=YiYC1rDxh=ncNcyc3t5zUk2+gFD~BVca*Hm>h31dz7~aHCN5g8;dt_hq_?K1ir2u zw4YM3q(Y=)&4|KEzsCC5ZlsBgT{x6M1YfaNH~I`hQ4k46 zMeG|8)jm05pWIa+qr@%XYiMoOQ{q}}muee#=MDPKEO4YWq6!o%s*@Cf+NH0@`-<1V z0Qsby@D719%8h(kl6|)wBJYBdKV7CzfpqSGK(V(a+kmXtOvOx~%~hV0K53B$h#j`P z+9XOM4Lp*`{9cGledb2Jt#*(Wh%r=qgVf~!H%Dq!Vr#X0!KY9H`ubpTilXHg)1nwa zhe0-zMzTGHi`YUy9Uyfya+e9R3{=R_Rp;g+u%F%5_1M94qMN}CqOLp0WueUgD6sUk zltJ^kOG_IBW;9SbNn2nMhVp9ebhKo79gl#KEjR~c$%bRshXYsl(HzuiVIriykOwkYfXS$%`&%R|l+b&Vt$JxfQu&r-FB&6m*x+(BBsVEoR7xF2 z%`7g1CBl2+jj4P4EuTy4=9Z=xC1OEe;IXmNy6#v8OAju73%eE&DC`W z4*_xZsfhfn^;2`IWQPNp7b*W-`A+B-C~GC%%$e&W~M z9q0m`Z{c>$jAv8cKquRr&_Y>s^}V=-nQ0O99$1(F@tw>Q358C-GR*PGgV};roC|_S z#b+(adv*(0KGj+GhpUBL@I_2fgy2XTHenRhwFyViNl){&DVG9UkRbbO<4h|p>n3@y%7=lZSC+J_;_FJ_n|Nvv;OSMLQyNRdt8 zbJU-A4<_%pA;`BDiREPoy+v}A_tdLuvQ<)%O``^!Q^jr%JQJ&2N)Qn3)R^-TJ?MJ~ozjHCU&Pw{_ z;?Ifs!bnuSxF!`uwa-*TXH@yNii%~RN650hiyWqViglQ4lHX zmA1tgNm{B@#2`aHS0YKVvbY!UIuG&kL;fYnDe;tgcb)oFP-g7}mq$bR^dHUQK!(4y z{UYS<_AB3g1-Tmtes2W%sHC{R;*kWle^oyeSwQA$BO>6c(~|lU=*+;1^)Qu8g%8Br z#|s)kkBntD$mdU4>|N#Ald1q2BlI)02wHMzZq?5K52mjvm%NladBd%yatk5ZN0gy> z$r5uV4vhgC*$kcWWf>$qQ3M;qyN`DC+j*M~xIzO-aUZJ#9 zA;O~nq~^wK#k10C8Ihul0MHb?W&p8yHEW}yVZ`0&7w8lp+M!l3+>kRxsEod40;d2O z7OgfA)!>LSdtqH2{m1SF1!%^Z7Jl zuf(43Z9M3alf{NMAS8~jL5&bWggSq za!^3j)<3n+Uvm)b>?lNG+XY_&yW0`E!Y(%aYm*zpv}a7w_-mfAUSfpxZ-RW}31lyo zevk&0AKR>YS$OQ{rpw7ZxI>Z6HRSZ2)$X*b0+R|PmUc~zYEQ-UXWJ(@_=b8tT`+H* z$$aW$5c(9_3tKnJArxQKwfyK?;WENjc;8%d7LDW-Z?qN5zZB8m4+kkYXs%lHiL&vW z-PO@Z2H(eITD6f;ipS$mGCs6hV1cTd+cbY;t?9$?@2Az-Q{eS)9cNv3Yw}L15az zE=Gy*oU{HqO$zfwbhqV|YoGy|cZOzWE=VDT^Q6uF zk!Jft;J$Xw=pnE?NjL6wLFGwhc~3rDHB03ZHsR)@xdpAm6_q6Cwb&hO0})>eQQDs7 z(I=xqZ-`G`g?RS@3{b2r$%FZIWv}ssS^uuEyyr@I%Uo&ZQhxWZP%=#(bmJWx;}mxn zYLL%XfY*y$h>@G*H7`CxvU34RY@cncu5BTo;^q{Ne+6!yJJa#8?2LCw2Mf4=3vO<^ z9&--dl3#7JMSL%FLRuc|76UG1J0Hk^Md9G-tAY3>yLmPN` zagb-%n?tV*EHLkR=V&vg(7S*U-@g&X9ZpTR=Cia-XF51CCm8)mQ5>O zc4~YptJ`WhznIxXHvvUt5Pf&_Zj7Fv(0KV;^+nR(Dz`pSXc4+~=KPmS2zSqY&>3Z zy!)Bwp=mT%iTxdHbEb-24*qi~a;G zI%D@k)nO%j8P#alM5^ucjc)w)nWikXyV%YC*(8O3TuKL!OFxjlXEL zR!xJ%JEy-|C&qnX68J?JL{lm-=)xlyA7D;v9?iQ*eVV~@>S9g}=w{H@J4@031C2m( zzZrk>PM1m_NA$&c^GApESl0=z#UvbIFajTm)@~8O(}174HXAsfHjmD+;={QNAJ3!% zK?u+~m-S|McKxAfQaXegX_}SWmszVHG+;UU;WZJe3#>5~so9l$?HM8fEjsQ9G+1l` zG&yT0Br^z)V<>{-`>AJ_8B7?YCDCAUGgf=|ceb&X4aKDYfB{3mkL1I&2i+-zO$0bl zD{MA+L2!XSA_EstkU#)17x-m2z_c64fVe{ zPzVKtNQg(6`E-|gTK`BUS_p;L`FCee01DKD8(4zW7z9$I!267hHgEw^qys1*Gj=oO z?t^h40H+Wth3Xmguxy^YI)ordy<#7E`UIbka`kl^$f+Xlb3nftzF+V}Z~j;J`&0MI!bkoiNB%NTd^kb$^68o! zW`zUnH(D4Z^8abF25W>obcSTm!_I$p62UMaXdWBuh>FUQJy0vYun6sA2-*S{fIt9X zAOau&R9pc7V<3xx18V@df&l;@Ck{6W>H%jA5DpXx&f#LHL>@4DG;mZxf&mO14gv&l zD0Ak_m^5!*qzMzJPMJ0b?z|Zk=TD+Mj{>a;VCYh$PJQxZinQp{s#dRBRiI|pf`PGi zsd)fEfkOqHLLDd|!PF{K60pLJD|as4x_0m4&8v4W-@b4u#ML9>&?X!TKLFU0CrCtw z81@(%dt+cBAEhXC0b&Ax3mXt*8g#gDrV<7%PM&cwnc$EPi5^6mGLT0}4u7<`05Hde zBM<9#trGA4Cp?mXJ)F5%j?gEokt=5CWw| z0%wBoQ3G*frQyN_dbkw97B2W;$R0~=;6f4x98gzt>LsPui$eAF;*3w-2qRq&R3Y7T z%ETg;ZUC?{g90jGC*i zyYkvAmU0mWmY_!pT{bmVvjXVyXk5QuTtGA=dM!iT8eI^zG9_982%EW1F~35XDq;B6nba@Na4z_ z!w*9ov3ZHaMeK&wwix5O`DRRSpfO@ch?@)7)Ul`?J8Lp?63d&MjCgIz@_FnvEVIow z! z6n48*ttl_rD$o1zr(|pFv!!g8J9VK$;TtM)=C)n$&qfdH>bmBR{rA2<%`JG0aF@$9 zd0s2txZ{sMxAoLJ_Uts@J0gCxQ_FP;UaGkGmydUT*6Q2*8t&C|AHV!jdS5^A^?OSY{@%W?KhLD=Z$bIv-%akf zKdkZ3ehIW60~@A51}-py3&hp`8tA|GK@fsFn_&MEctHwc?ST#KAolR5K>rUCaDcxX zAq!jR!WY6YhBBO?2H`iq8{+Uu72M$L1n4_v?aYB#DP8}vm%Sb$(1!v%;t_c`z@s$L zDN$tD5DN&v>IpH2SU((lG|#v8uTi*lS}31!zb z(D4mgQp42Bwzx;<;jw&o1LSg`rAIYlksx&R<02dBNC6hiC(4>6B`aykOI9*&n4}IS zFB!MQO_GzH%w#5ok~~prvXi15;r8UN2NdYk4miMAKl z2{N7KB;Ps%X*OkwQ=QiQ<{0T|&wHBkUF?+S9jV!}%tC z9!V8i(wjCe5A>i%DN@?LA@;!vEN}x0tZ)ck?lVex_}njTiqoh1N?16W$2|VA4WEiG z410ir9$es6Z2RWKF{Cb%Dz6UF21DdVCSJ`!cFd|P zvidc!Faiux9$^l1kRlezpvGa-K!kJ3JpmP%pcEFQfC)_aj!at9gc9&zXFxcK0#LvLVXmhT6@cl2$^Zro z+#m`jkVF#hG6*K<;V2n!1Wn5D11Pki4+lwu2)=NxLZCKwBE_w48{EAhsKXxZ_{KoW z(GGj4V+&{;mL3h+&a`YS2Msw_Qlv`P+|iX>iTmVCB(R7TApr`;nm`RC5Q4szWe9t~ zfCJ2nz!M{|5M$U(iXBphvFJcx8%TjLn><7^On@hm;s3)DNDP57pn$E3@qiYh;0TK# zpt-VrCyC=)W_|W9i&;U<+s%fDOJ| zghMdozl9K30xFOJE(AI;JP?R~Q{a(iPU(S4bCT&2%A8zx5#Aslt4B&ti9&pl& z#3B^4_|GgJ5eu3SLf=i&4XfgSLnh+o&2e71c>m@Mja-x?6>aE8DsCZ-Q~=-~?E3&8 zG=P}g9O4)oP(dMjP#`xTh6|6GfCbQyffOVL0DoA)VC>L=m3)D@nYKYiKu}$_mf$*( zv1=f%U;#Qzp%g8UgcV!>hY=J(1iFE_B*|ieGo0ZwW2wTUyN!kmhCvFzSt=Py6{iVk zCI^%5GPi5Yhx1zR!0?rC6n>y-9^7CPP z-V}TXVLM|(SOB1gPbY&ou`t1wYAv1UKp+lDf(3URxn_o=o@@8`dN{(73bnGL^}69R zLDV3H&ER3_OXxu@Fx`he6u~zn$Uq;YK>r03)PgayX+S!JGpNN05&~Y~Y%RFj)yqV1N=T(B;RD1=M{w-;$&d0tevW0uPXc`zufd z1~JGKG(aiD!5a`s+ik*YoI!qoK&<^n6yU%Hyvoi*KnCoI8ARXj1c6K31R6*|et8wT zeU-7DS7gZ;0H8oZ@W`mi!5-LE5gbU1#Xw_#3j#EPcDw;gbO#oM#~aYXRXqayEm9Mm zUg{a4!yLjW0Duyb!58eCCwPJ~tkDpx7#kqjCMblbImvx_iyIgjWuyVL@rgz($ceyL z3T#0eoBtgTF$_XYyp&kX08M}y3SycQ92pKEz+yB3 zgv1+4grOXm!Q@#J4wT41L%9X2L?ttV zj2*Oqw0T>zt$@g}h!gxk861PICBPZ@z!1ckZ)oE&fI$&tqh=Ks9y|yo2H)_BfE=`d zoA5zr!GRru*)dEb)?_0UlmNyQ2&+Y1H|l{S8~_S9ffh_a6fB9wj71JOMD?KoA0(b2 zaEP=u!L)G!)~p+g$w47NA_ka2Af!PAaDZFFB`CVn)*%60$^;r381_&B9du?FsA9^^qBq6iLDfsh=48hF`~NB{}ofe`=!6`ocBu!I(j+;t+s z0L}oSh+`|}!3WU57?hUY&7Y!dU1@zmH`)pj%x7jHhfiw220UF1a0#PmKt$xCPuPH( zM8ry1L2SUl{W-uKXn`Gs$wHVGca=p5)WEzMNgmjM$MKqg9u*l8Nf5Y!hf;wVNZ!uO zK!fI}L#&AST3lM2j7hMquA?v(844-z+ zLPiq-tm?St5Vz)x9novR3M^A~4!;tG!451VB~-#PY{SZru{vzTO6 zYV4>K&;Q1H?8ky^#cEy1l5EMEtQBFb@TBa?vTU54Y0JWF%*yP{(rnGz?9JkA&g$&W z@@&ug?9T#i& zl5Xjm?&+d#>Zk?;BP z5&EhxA4LWLNI@H}Z~RsTBJiF3+AmL(9DlXb{l@QVdZrfgZvf+(phO0y2C)3vfH>+w zAslc6Q^rRul>_sy9YlcyJFun3Y(M}2A^8LaApigXEDQh}022dg0*6OXOd&BpK5CaN zG*2QjKo=n_HDHYwCpAB7n9$YOKWv%a>lg z=iTAt+TY>a;Nt)P{~awnIAoL4*V?VLyQ8bI&C}S-(bPa~n;IoC#>>w&W0B(J=(oPZ zw!FX(ATK*;l@cN`@$&M$!pFM6#3VFAKx~+lo}|Rd&3=fFjFg+%+~1U&p~1(?D?3T1 zt+cDMxYyg?jhUpFpQY2;+v?qST3ynKD65Zh3<}b*A(6^_iilo1>~oRbX>`gjS>3 zFFr~-M^nkp(KbX-SBk7MUXAzo`Fvcn*4f)lS!F~~T`D+5Ej3W?@9;oQT8565v$?)e zU1-VB(_x*)VW-<>vFB=aepX^^U1)M*Y;}Q>p*>1gW^j2487N1P!xl786B{K~fT1>V zp|QBU1QjGmY>>Xz<@^2pro`KxqM}`uy2!hYTGn zE@_#lue2sML}shoXrRYMf3S61sf3P~vbDJ}UWgJZKmiaRXHc8D%h`^w$$gEUjGe8F zU&~!jicNKtFi2fjNQhgP#&}qQI`^#@gv1C_+?`yN+4X z8$errp1g2Mu7Oy;slCi6Gd&+@|`o@cJ#>;Lg&xbUN{w`H57+4lKl zM4bQy6W!NuH!5a}3>YNAv9WHAs!7mN zf#ipX*x(;)GzCE%mu+2UH8a26*5dH?u_n6>5DvuM+*UCXwu zTZXp?b{d(r?AyC|^XlEpx355B0&OLvgD@!3p%m@;kqh{j13HmKo-noTH?hiQ43 zAw)Jn!r_T1!Zspp5meM-iZI3~V^asLIOB~tmS*EgH>`mbB0c0Ne0K_BALYDwQ%0OqP z>5++C40OPU2$f+_7XocTUm2|Y2|yiR4g_eKj5ey47a7Q@BmiERa_F9v0x*d<0=eP^ z08I!KkEgE0xe%ruPTYWsY_ z&;Y1l&?5=Ou#mm59`tKL90bdD53~|=H|BC5QBW0u#;v8`wAY?kE&~yg`{V-YzNA3k zxN@>U4-_^4=XX?~_aMs;G66gr(Qy9mn-;J#aKHS4XnzI~QH3V-ptLcpfSAHo z`zA=iH%TZeMgZFN3Mi8uQSgI;JD^@_1i})Ua5)@2p$b=M5)W=gf=o$aXu1SL%CYc< z=s{Ud{IwTEAOvO!Q6JC$;DEy-LI-{=`Baj27r)-ogaMq>3YIcbCGGVLhH_{?_L8Lq zBYN>T78FPx5RwN@b!m2FIaT*!Qice+NR0u^&;FQ}sDdcri+C)~rk0w`TuH!lZu1kO*oGB^z#wUu z%$8YH_9}WMDsBxJ+Xi+}N1bu9CETmkvi4NEgHYjEQp%$+cY`}l<)RS9iv;8{C6H4b zgbB~+T_6bo2~jlTQ)v8QLD2PsC?INY1@asK9?=3H0xfP1q!RhgR>^?`f{5269sU+& zgoVvuZ3iLW8G`2jA2HEP4d<*^t%xAb5@=xzn`9ccMwh4)4D+F-Q5-?A=>SJE5mbfD zLa6uy3{iCynaw;1EvF^BMd@vMf5Ds5wrD8*WiFUtxTVi}5L03yNtGk5+X?^>J*u!0 z0Ks(Slh*jXB{0cKvEm^_ms%NNw84V7W2UCU1yUpy@>_gJq(GSP(S)o)2N9cFe9|D( zi1gB?DCH+YULXN0AOQe~_`wbK_5wBx0hL6RXZ+gvHt{h42y2}oQwLiaMQTbQ*gR~y z4$^{VXcYil&FJE^-sjQR6wVlX{PQtUF^VEpgU`81;Kg zvtvsd7F5Fj+O{#1Jl`_}nb<;#OA-lr!<&pmkjQe%Q&OcL0}En@)Pal$Ib*3p3i>*M zyvt`my`#g36~$IsB6Hr`sR!)yi0lQypHdhv2jay}WZ^1TK$Rc|?y0)viC{vqIzaZE ztK9yL-cPzQ&a!cEe3B}DM1&#IvY5C05*I$@1UMVBnnBnC zFt7Rl&2WyhoMUWens{?FbeyxE-$LAoa2Xg_3KyC&!lpz>^i)+|fpDtKWQUB_h63_Z z3Y5I3NoVs)dSbMt3$$4iA9&B8?uubGHMN5{LKz%11pUG#xq+M-K6oI=neY$~GsY>a zqgIG%KcHRfstyZLJiA8rBwE z5K?5J?QQ6J8-O8;#C8Vd3#kxv$wmatL0V8;D12EfNrlb^G}O{OSAqoZC1J0%RzY`xh0;1bfI0)AHzhD^;5ULV(P{v+V8kP38DR=a z6e*?<3hHJA-|&JIK??_zHpAyPIv4?AQ*;OOf$*|URKjIcu?E*ALr`LECrDo22PGzQ z1!}-KNZ=;}SOO-HMI@MoIq@R=(P&)uV?QPz^8sWU!Dvk;c^~EgIFli2_$6S+K}-gA zQ3fD#h##7kW(X7?aj1oSs3UDAKME8_d$WXn5^W7}gMTQ9c^GYpxQGe=(TIH*iIO;p zlvs(Dc!`*piR{4#3ML-PLu{HDiZy|RjrM3rNQb3JIcteMtfiiiu4ACB?$~>HBDeC zh9(XT0C;NTT)H@7ED%M~vPBCpGn?d63ULDr)oY*SVXRV+&_V$M(E$ZGQz-*oGr%j& z!dD2fEM2fJgI6Vk=Pca?J3y6J?AVfXmv02Idl+SldN7l8hY9-sfd@>Giok*{H$VU@ zKw$`heLX`B+2{ww<`7WOEOm1P4g@0Er-MKxFvlWW0<$VW6eRXiSv$pi%lBv!_$+{h zE^?p+Cm;r_@*)>dhaH(SLE>gEnTb^+ljgTIC)hC)5(&a^4T6+JS~G~B*km^&ZQ8R> z1G8DI!6c-ljv!N&QZ_GTGb|3kQk3UE`1AoMFbDI}1KV~Gc2FQ?b7|f)ebCZ8Dv3)p z6PKzfcLos(#8?otXElB4M37R526u`E(JZu}G7V>OzDYk=z&b5munpsfkgQTux*I zmU1yI;w?SrM7*<$3L!19vIU(Kc9embRDyb|6rlJcEzC($)`MTOR3JLzdd||KCL%kJ z`J4Ep5DiFLCrNE5;AIOMiswckWdI^L=4mfE5d;K?B!Xf{wuA&wBk2?YVpX^HU(p6$MJ#qpC?`BH?>Rx~8$Hh%e-(;8bU3I;R@41ujab zc$%krNyPd69^Escm6F zi+~4dM-gbMf*6{cXlRK2=a!>tU=!h4l6N4>;%1n_m`#VNvKkM2)JKYt3xK3px%z%4 zcrmvJD)@*Lm+c zTCysuA<&n_Bw3*HG0%X0laP+C% z0wG$~BU;**pP+>UD_Exk*YzZeLPRDIa1Qufl~eh`6bxV)gM z5E{milgfxXmOw<*A|n!HsOp)@^`sg9wk!0rC{fw~ky zQCW>FfC>!oP3ZZSfHN6p3?GF|6{>8=k1<>avBJYurtj%4K8>ZHv?}~d{EPE1aSn-;Vi=ap;s1R-wg|i|~1(#0zT#?l)fOHIm2ZvU^ z#3fQd0x>Ys+aee+1Pvo$VG_UrLC_*K zqy-}ArN)W66s9XuCbb1()MF!&V^SdO5Ve7kW(EB!6_U_MrPD{@(1+;1R%Q|PTNrhS z%%>{9DMV#(tv|3RI62K+U{cm*%@b&i5EYufBms%a^`$om)MuEa1-5?`13^o+*oo2C zl0DfA^4FAo*=Ru&cZ%7Zo!OoJ*?1uuY7N?PP1-x*5@u$eroGyJ?PsPP0+!9%wgJDH z2HUoM+qj+Euze-E-P^jD+dk&o{?XgSUEIcf+yi;s%Dvpo-Q3Ro+|V7}(mmbH4VJRq z+Si@k4UG|s5!-41w7`&t7$o7{vZ&o}M&27S8t82jWwGAotsXcT-|{`*^j+Wfec$+< z-}hY-4(;9u;@=T*7&IhUkv))n{oc=UYmkKk4Bp@l{@@TE;SxUK6kg#FKHllQ-gV)I zP10=N-KM2IJK~Mt%pm{}aN-LN6$;RrAP^F{0pLZ!67Ag+c2N~Dz8*Kuhl$YQXtClK z`oI~HHVdQRJQ}71f8R!V{1z)go zrEU-gaOzv7>JVY(GBM&%PUVjtz;zz$brk8NO6eqM!3tp{CDRLw;0T*a5SvPS-kGbR zK6|rSTmX;`zEw!h-Z6bX429$bt_}e7un?ip)t5l+p$+R&{t_B4i#2`|HZJQlf!1{) z;NdQ-*N*A~5lwv81f)O;pe`pWC#;6>1oJ)xo9-#i@T=e=5S#!AzQqZXlkJ-h0Mxz* zrM?OP00_e{0&`C2qLS^L&fiEi?l*PoV4>^Wjq6AL;T~S{Bkzjm9^)-p=-CMX(PSzQ zFamx5#0Q{m04qKPi(m*NU;u>>O_LxC^QZHs7V*{~5QO9lMGx^#zzI%(j9-BC%zhAp z@C8NR818KtdCnIg|K=cZ7_YJQd@l6gq5h3Y&Wepx@;0bc1NCmNT&&95%vvyP|#ZZfva_(FgJhLFV;+qXLJ0w93G z1rZ9q!0EB@;{y>3G4JdJKk*j7RR$mP6|WX>{`G7<<+aY}mqGX*|9c&OVIiLQt0}C` z)U?EJS`>hiy8!gwJ3oxWB1sKBB=0@siViJ%HvqvTos_N$)yr(OH#zWr(c zsO7Vd`?PQM8h;XC?~;(;Omnj49kuC`@c5-m=7&|f73&5}3oe^4_YqGI^sxC04-gsv zq_PG800KY&_81gm5P+af4kMxv;KJcWj2Sg<Kl5CJ`cy;tSaku}9p6O_#3!lY?eW zKZX3)X>Y5YcmD*gaD4=5KU#Tv`0?e>mu_(``0`}6(&yjb|9=1j6mUQS3G}8ws{}xBK?WOi@IeS8lyE`{ z+hYtQmnzh7Lk>IikiG+H+c2vSOEmFB6jM}@zHdxy(YDWo3u-Z%-s3GX->5n*$qgNJ%c^lygox>x_?0J@V9ZPd@wf^G`qn6*N$z^tAI(L=#p2bWuhdb@Wk4 zBb9W~3>?bfQcN?|bW=_{_4HFvLlt#YQcE@U)J!K;byYcqoKukq03d(>R^gjf)>?Db zbyp8*<@Hx!gB5ntScf(CSY(q`c3Ebdb@o|kH!L<qGff|fF1|X1&s419YwljHs zZiD0o0PcZWupDf=FXEi-iEq)Dj*LYY{CMQ$2xp0Yi^!)0oFS-=#rui><10>*l z2xpK3PAv+FbI9EQ;I^I|%zFS3L(2NsxsYRUx_e<8-Ds5(*ll67W1-2w z)w%bn!2#L|Ass0Qz)C=_iJtpG=@hqtDikhlACr}~mZyjY+5vhVa7Y&c(18@ta3dYy z*ws#eg$vlPab9!N1~-y7jznOE01%!=`u0Xx#u6y!D;BM2S;Ph6iU3}^APaM1OI_Yd zm;Hl8E^QgE7K95aBv4)94lpZU2~%6NWF-Ei^i2K#)vjc()LW&d=?QL%ZI!YlXE~{& zOlvkJg}-EBtk#*69{%K=DRJk=-Z@YFArofN%%?BS`A>jm37_W~C>7TU%z!2oK0i}v zLmm21h(=VR6QyWHEt;+(UR0wSxn8sA5 zGo@)wZFic^~Afl28KDUqVold^(Up%1XnK_Ku}xW-kkbERut?Rr#5luR+}0;cqy1=*(&g?`kZYAmaAXlIYEpG;YhKMTr@QNwk8wMK zf+vVbHBcFkQ|gPI`!4r5(9MyRvS}Ds1z5SB^)HWT%U+AR!6AG&g+Wfi2eCZ(A`o^& zeCr}%0E9O!Uy(0c7lIqyEQBTIm! z(!mZ5ymqe&5p9XJ)YZ~@dCZfhOBP6>fm0X)0-|+;2AUAw`A)&DugF4=dr{+OkmoiE zxyT;E;{@vr<29=$3q8alh_ZMnyT~!|fPKB)|5BQwZoq>9O5J0(ETYpHR*Rn9k_96F z7yzeciFFn&mP??8AqDXTL2}&{5i0`#d};Qo#O#>!av5O4mZ+#FA%tUZCD{sQNQK8T z-YKB@$Hjg{wK=h91dQ7pBd|vQU*3WdYlt=>&Avn^05FV)YpAp7mGo^X9&CA8*Qyvl zH@oq5Y_YsSE@ct2A)XM~NxT8ba2`RXoA7dEr$#?}h4{7s;qbGh!YzRwi!Vrg5E4td zx4dqSZ+OB`!N$bntZfL7_Y+|S-5ah|p2RiEt&x7fh&H%M1v>yy^C@fF(F;Wmqt&R;0dgBzrw!7!gpi$Ui6?B z>CQ+3G{`qd)OqTM-#oXceQ2KBrnHM+{p)9c``!P3_($G6?}Mf=1BcM~=U*q&gyl%} z|NnBbKLGqc|9hbV96)9%KLm891#CcaIzR`Ez&U9i0Fpopq>cg%9acF4B)UKkL_McS zsgB5{H=)2t0RzbSKoyjZGg2A=I0s|UCPY~QDtMa}yus9JiazQI2$T>i2n5#22r57r zUpfZx2ZNA?dq@tVSb`^V!YtAW5ts@UXdj0N!qp)kn+PI< zu!74W!X{ipE!+tIDZGd(WQC0ofem1RX8I$wnWIE4ZxVgbBHW_8v7}O6wn^+ zAsip5oSUJ71&{#;cnVhd!i$-K%vpgk^ff793F1))hv>wcVLmqeynW~fZ2$mih=zFp zfM_rXZ5V`8x+IKAAd&eONFajJF^GW~#0Db4jbMO*`4~T7f%GB4I*6mA!Nc`wq(UT$ zL7+r~I06S+q(#yfDc}IM(Lk0!9E@nCPgI8tXu)0Bg;<$|j2gx8;|2iGhHc0mSJa5v z!5sFv9UF)NGPI+M5CKVA0L0M(e)J<*Apz&Rm_bS>B>I6p@)9|yno8)1A*ex)*clvw zq{%tPj>v%jKuo19RHF_=C3IxJR*Z&rw49Ix0CjX8&qNf(MDQ<#v_0kme`?6xqzV&n%e<@Oh`uDK?L$aog~zW3W`SR*+zr>m>)QTGXP4x zjGm5AfhEitUwi}*awWpNO7=^J{evC~2%#7_0q?71FqSDf8nKG+9V1xr7i@QJ(A1!Il_iq!U-anemS8Q6d-7*B*Q$+ zWI#;+00>UuteOmfgLuiPn;a$?NJ4a~%K!ob!U;x8DVBwFA~JM{HRzxk5}hJy8SQBb zR)`mi`5~xm8k;GiO}wLYu!V6tp&4p`Suh6p^u&^Z&)Mr~9_ zeN;$|R7sswM|BHvQ>@|mt8;_C{`xgBHPmLYEYiZf<7zx{JCDk@0g^G6eyM zfsAjZ*9T#%MhgXpQ#Hhcyo<21M^U$I)z>z%*Nrd+Hi(Fbc!*g84;a}5SyMFsvcM0w z5DQwxFJVPgTI;*p=-A)ek;SNr-k>f51wn*Gm#i}fi2E~&a0@CEyI63v@=y>1$XP+7 zGK~;$m7SEFb323Bgg{Gz zp!I;7bu>?~HCCdeKzrDrr3W@(noBST$efF&1-BRsG`ba$4NHq~vs=K^)zVPYUu)K@ z4VJ9^1Al#hO^CsM@P%k3Sj7dyluS5>u*${73%M8uh~u`5P%?}Cxj!SZ#tmBl;Dmyp zhu3I}dIQ;rt1`3NR-)55l|4FiO|fnb+zD|!r7;Er=m%SKf@+Y=9gEjUhajY~P3T>;z+G1BU7i!#{O|?j z#XW>Gi0H*wiQTr-os!tqADuGS%J{8Z6~$-8R@2JY^}Py)!w7481;_(lCRm2Bb%9yy zUiftjb4UWK#9nqVhUN|5FJK3(s|&g~;8wd0pNox+@LnEnG!lzoM$uI1n>dp#*L9T) zo&wg>1VY4A3@Qa0?I6h0tAwhv*0YfyD)fTL!O51zEeD zfm0e(;$b8ci-J%ECu20*NQFe;UWNeOJ_}#BK;j9JSE=nUDJHuqmXPmzuO~~3zE}m9 z^plDMj<@^eWkFFDo9_ieQRg_-o(io3#fD?vpsa+-6=Bw7$WocwN5IBM5(ekbRc+(1= zT|}m3lg8;eq25vjm~TMm=^NK=HoweBE59}B)C(UQxN5A;e(SalJUu{bx~}Uk-737!YrWoUzV2(k)@%7NYr!6D!Y*vX zKI{-hY{hOQ#cpiD_9wf(${XbnCXMU{tn3ECY|Cb?j??VT{%p_=ZP6a>`6F%9u9Yo4 zZPi|F92}_(BvN@|Z7fagcW4LMzU_-R1W?ctD8+66_uFmXW^H$9mEfkn)D8xXD2I(0 z1ps&lbf}7Qcn6G_hMair;08P+tgMe=a zH}CV#h$1L&hp_ILafo7Q?qDDW3lE3#CI*KfhEf0k46pD7_iqCqMRXAFj<9faU~d(7 zhz19MV8HN;@NNn>h(pkbFo1Ay&;<5=2ljS{5;uq=m+=+Xm6M*7Prz}92!>#ohE|Ah zUs3W4?}!^m@-UEbEO!Xo1^{r#Z-e-98+VBR;Xd*uUqSC?ZVQ-}%!15SR2_1h5 z_7-xC7;Xq(b2g{(Lr8J$4hADn@lQ~055I^~F!YXq??gXyj97Fe@AE9LbWIR+KW{<{ z&xmpO1nL%V1lRB~X9*!+@J&zd3QzAHFY`CgbT%CGjevCl7xU&u^NR>`SeJD&ZwGLw z^7wX$Di8CY7zbD9l_qBtUuP%CHppaWQDBG8WN-FoFLr9Lc8^PKYhTu5&vtI_cJ(X2 z4p@N_5cidtqmI}j(+SV)d4zTFb}z*u7sZHQfb3d;2NKfC+JOaoXKZ)B${)DH?&JVu ztR0C23fn21g~Y^Yw1Cp7g+A=}HB5H@SqGmbAOb|Nq@4jCj)27O%tsxV_iA(-E+~N{ zGy%3*0a$=|CNu*xn45KYp6O9bT!EW;KSPKAg%W6@4XXK-p`V(+fifrqgh@+%mqC?Z z`Ie_36Xk$-iKip_0ADY7mRN^%fcFOCOI&eyx=F&MKY9;j`Aus2lsrp&=Rlsn2^K(t zUyvGjIQyD_13XlXK(L>m6qHR9U_}3c_jP~)AAkoWpa3A~B3M`fKY#+r zB!ROr!<3g5a#zE<|N5kFNHMp2%Cm3Ich2?|=rmuVzwENFb z`j&5n*q41Oa{bpggLz*EiMRXzcK?OEr}ffj{SUNz+n=FlCw`7_ecLboU#AM@7k)|u zZ{sHt&xU@mdVUkBe(R?xN&s#w(f;j^Qt%Id@-Kh$KYuR4cJyC=_Ghlo9Qy+(-bx%a$@{(yVFoCeEBXck=A%6J;QW90&$EQ1HaV6GmtnjrsE_ z)TmOYQmtzBDpsC33bGtS5Y0ia9-Tg1YS1i9vRT)%ZR_?e+_-Yt+H;tp3;+`aDFEQ{ z$e@HD26+HjkdcnTU37N;CEVpHaY40nCsVF$`7-9rRO<3Lg)0Py7*vBX!qQuiG7vmxOWaw4 zj{&G7h#MyG@Z!glFK<4j3MvdG_eC;V;jw}r>HxSxpW^Vc-T~8!eEvUx0SY*vc$_)2 z-f{qRk)Tls8Fmm~0AN9yM8jo(SPB%T@ECQZ*^&@g;1M_?i6xqNVoL>ZlwX1bv8G@R zf)ykhOrjxmL3R`|CZcu+*|HrZ2Awktj|YW-B9ciexg?VxS%}b!?7c()YYhZf9{_X^ zNmQ0R+K{D|#UWPzr9vt;c_x}^s+pOY77YXvdl7YbmX$fCbZp7^;=YNyDsn< za_C{`?(Xgw7`nS-=#~a4X@(H#j-ear5|EM-r8}er2>}67R1SMz=e^E8=a=(0thmqTkE5nI9 z_up-VzE$Slf5-R!@9#&xAs~)4|1dgL82<qGxrNUeqs0M+hrKhQWDfb%Kr{ps;e-^HkS7K ze$Bqy?q0!RbD%T${eF}Cq8+L{E)=Tx8Z4<>p_ukXh0H!k${m$nR3IS+Ghhx)%{pxt z9r!vpJ=CVU`)i4Ic-jI+_P<0{0J22%xL(W(JcG90F9b-)61-u1^VKV4TCheofD2yP z9CFedW!+z$o#_=apZccl5jx05914x$S`ywSRv?gw{ z)%hK+K1Pf*S{63cM?@&?b%bLD!^-ajuv3RU@r5afJ+BPLtWPMd53|5k5yjUc=RxTF zDYFa%jmy^YGr&?T*4w_aJo)3l22WX2oQaP2Abe6o^x+hNgGn$%oK;7iA&4wv4Z3m28R}>Qb-UbYws%0Nbco z8{sibUtLw6NF?}Y7UW4D*;th!Zj0h#IKe=d#?okRL_NUmKqGhpx z^VOPDFU?$KarBwqY^WM2&6f$FTVJ$>aRkj!W11kE(BQd_3GV};5;et=$jA*2@nx~kEsm0D<|N1?wI@2LN{dfG?g;#lX&@f#C!V`25RZBG# z60)Lge#c?- zQKoJSypHWn?OOpW@?hm_Se~@)Y8|}sh@_PwES)xb`-X(a#cyP7N#DsogoejWY+6mC zEs(RJ=|Y<@aZ}?$RGR<%qQDEsvU|w0#~IS>BgNSrDA3*eIh@zOf@}L!zq@b6iVT)k zxOL&A@owucZ)ZQw&b6#Y|Dgf9ThD?Kt z5!|-qM9hkkx+hjCf0!|B%_frey#rfsDRYM0*zuiwsdzjb^{3ZAnh5%ABYrSr|6Ql| zFcvOO$pj;Oqwul@al#gZNnuPOONqQB0jj$!xXEU`;t;(U&S=dH>H`)<#IT~Uj6FuX z59TKI>$td$+?W=?YFm@PrmsA!=Bn#RzwFs-nlR!R%ghB(FI1Ol5s3jUT%C6!;q-mF z+o8gg8rs!k)4c8SbR{VKOaj5xPx6Q&g}UNElkUn6EJexRN(}{Mq~};PX`&}H@co1$ zDE;v$;=VgFULR+`?l|ZUshKf2b-#h<^0`1X&^!)+o8&7zhIrk*f`AYmYpUsZuf-w$ zz6iC(sm6k&hG#F)r6+osNs}}&3_0c$WZ>6Al3gyC-R3bI@7w{5l!FyJ|5Nu{vzoQ| z0s_2BPlFSJ=qi>rh_ur_P^t7SjT!@~AAG?3qS>{)yhMl z#jqxA|(3 zZh`C`HSzRUKUR4xIW_%14;3!S7xIz6`X~No(uIBqD2)!^ai#yVn@>qOX|UUADEitu zxkYuDBkQjKy(mw~cfCRYzOod}EUqaq*MAsYo;a2Rnxksu<8RqZ0&_zyjFxSNo7uoQ z@))Hj!7$qeERvxBt7CMP5|J#NYW-Ne1X9DDJD|LqZqzx8)%=}OG5-@a));Iy-Ih?n z{P&TvmPoe3!xubrO0eBje|G663+#kr4EK4&*14^ZXPwk(A|YW#=JW;LI#k?gt(k_L z!rS}_99l7&OhLkD)d0M2ve;W z%4j6fZE5?|XY*|pBcsODz5soP8mC4lMLy`y0DK;7@}tQ0F5)7lKxTjT_XqZpABM%( zcihPtItS$WkM=MspTh`*I4)7EETy`qCauHku)Rsj=`X&2p0EXg)FeA(p$}06h{zk7 zSYZZYg@<8U1sDO$RxXb2Y!9yMO}7LDh^W$9_mn%rKxh~{HmYSzPVn%Sd>LgRYReD_ z_S&RRoG!dlBz(s@jd`at*Sv=U!;m?mLlvb%RnBTC-iipfpK`_sn947&*N+*x#mpK) z$6ihZZaGjm9AW}TeQTl{mWftw1^u2{#D3U;sBV!8jx`zqtj9|0_vk;b+bMVh1xAuQ zknpH7s=~j!C{6&FRhF&%uqmVE*Wq3TfP{IaSK5bUC?>VH5t;Nhl=yh+?t}ad z2!XDa2C(8HMPsB#S+-5on_Q4*tj^N?B)c;KQFz+ORATKNjx7|3b)+0~%}{pZM3j#e zB(}yAuSK@2Rd;@>uH!)$+@n%#Il$XdInKtWJa;l(Vs&6aBfTvu^fV<~Vy%^+EQw6u zrl>KGon-AiMp&&;<{jD7V%p{)vd@vyf@`KbR?eayzE2^oVhikZD%fsJUJskKJF13V zv-Zdw2Oob-b2KgXw1`M8eC<=5{>LnMF!v3KSvWdXs3l<6XB~z$;ZS0#Ia%?J!Hi$e zng0l|w#;T8{`J)%R%n%zNsg&MYr*sRcW!`FY_n-2b6#gYdu(fMGB1n2vRUR-VzH|7 z8-~0TjIAW)lf-40NZz~z!H+Q#N$sr#YTQps*oL(h?5B35r>)}o?{81!)Ho{6S#rGU zDm+X}TA0HbP84Pe)~sqXd^rm2U=fs41&m7tki0K{sTFnE8-(lLSnWb1D-dI+3Hc5M z|4vmJt;|FA({^m~IbnY4SzoG(e6p}fPte1e8DqAoL%!`vwQg=_(+l6xBLg{Az~c~O zMp{-UmE(Ps@gc=;dqTz&rx!$dBS$!MAgnfJJppzT`e6vbo=>E*=KfpKAAQ%fcp(xD zjT189iJdxa6ogK4goY6A5h|WU{Z0$C5XP(;{heh@dW9`M)`PozSQ} z?2aT(+iB*TFYLt!O96xCd_d|SFP|uFAn`Gg?i}N2eW$As6oXcvYcD=GcUf6Kc04zy zHJuX`S^e%$qfK$oVl!U)tTfhTZh(6WCK4C^~^G20vMSxB(xL_tdD>UU~lGHPoy9}4VDtl|oE#xb8 zK^&;w2_3~i67Rz{%>hsWWu*W;P|_3(2J!%`Bhtv1+vry)c{T>I%S1iQ8;|tXIEo!| zH>-`Xr7h#vn&RhNLquc4tDENaxisByIw4IPjN3(cykQ;;d%t-OqG4Y|c@LGF54CxZ zjGK?Fd5@i%kG*)m1~z|YZ$3%oJ@YSoVP-{`Fy2W z(E~~|S^X1>8CrkQA;NBeJj}j=t#0t{AcjPShllIVH&VBuPDFz_SgK>Lil)cFIitdo z+RP=)3+&o!uh&mX!^z;`!W$+%;^i>q%I+%1tlzGRXgqI^crD^7zTcM(QF4~Ya~J(8 zhWBta&_mTC-p+<43X8xec03f=hhuBwRjU@Jv+d$RCD|@n10~dht>+4B?n}I5U+WUu zIVW&H%H@IPQf5FBdM?3VrPAZbQ0sldYY&^X20-X%3U2TIkqL?(%;piM&z>#IB1eCW zVFh>sv>V%7)ge*4Og#H5f?RA>N!Zak^wYItvIA%VpH|@qMhVHXxjC<&HMdyXN=xL8(#5!$jg`!I#aLQF#}Q&@ zBqje10l|(Sb^+`Xy^O;ay<NfFlJvcUOp$U9%o~4*LgE zG-d?~O2qewKzuoy>1oZi<=#6;2p!>^<)bUJ+%}ucoT7 z_e}|5ZZN~2zWT4SK77uI)h+A$hj#beXe8Xo7*!SpBbk$5ok!#R8K4#%r#E?~l2sqA8({roO4;s93@@5h z=-adB>)$fwsbD&ScH`7YYJkjEa&tM4#2^Rt@kMytsn82<_5~{K2AJ-(E8fbRn*>I> z>;WT&$nCDsYlofa$Q>&7r|>ZxA`xw$CXsF%vHpDE`$)jdq0z5w*-HM9? z&tE3s^%%;lV3e#ZUh)i43tCQHU=H$BgQ%HDo$_disb82MTg7)3-E<{NcQKBkX$Ej% zeB6?5@3=fRBtXOqo7JFtEMlirp$6JtUtET8Xjl?Xbtd{3b)hbb;AE=7+g zn*gQ?Bp%JHQUp`<4;I!)<`8>)b%P1gZn)76%12de1{&$;VYhJr&QN|ULqK4z(wkDd z_#tR@4pe*jOMd75i=QH7nrkP^Hh%KGAhB+qS>dE^atSt&?o>JMW3M@VoMGLLtgM2Y zv?>jClu6MrHDXg&Od=6v4Gky-@!L?T$C?^any)ho=U}sLF6Tzp1)0*pBe|5p@gM3j z2@x2kLpwY9RrSC4Y#r)p{Ylu zN8z4mK}i4Hw|av%JS+2NSbjnjF!V`m2%5#5T+y~6K>D@bUA0WVHA{Tt1;3i~_WF+* z!EDS0mJunBF1AFbe=MA@iQwErV{LuOx=>x0x<3M6NZ8M%gGwnEBe8Z-jL!UY+F8(p zBP9m_j5e*&=>YJ#JiTV<$+|m@1sy410JpNfYB>wfkTza%N=sYy)zHoY&OWLjfM5y! z9e?Me%@^xt@eg&x>p$);7pU$((LDftCQ1_xGsNqI8p8iN)`_c>|CY7|uz{5U;96)# zE|i4-`mM#3Zc0>k5l<4PQK9-U*PSb;Cy+@hVONJyg8`*}(I4#B;!5yDo0v`Kp3=VZ zd5?f>o4h4!Ur$ij8z4o7IYxAdS9|S0JrF&wkBZEodNQ=@{`)FeEcbda#Zk2E_+QYw zx`>v2AhT!yza6eL;^1QwKBUqx`4nqx6MqYEqf+M+-NouBx~(pze|uqcMs}zD>T!G{ zIIvi6Y}4dSwrVI~Uzsv_omKNB6RnYzbjd!w_l|UF`7a6@Ad1HvBpjTEl;^+%5<5JA z8AlKh4%Q;^xxEi5gglg6;&TV%sbp$7!Y?6?>e*aoUH-oyPMY~bt}7iciJY~IrCye6 zLVw8X0Ps>kBG|3NdQ}?vq5;2&-3;pt>Wr%-7u<}SEP4a)ev>?TJd+3pfBxhPotSpI zQ?NQdl6qP8`kf9c`I>yz#uWXra`#B)Z95!;MHZMp0s(N%iQ~%Tty~|pqiFHp5?!N> z(h{(JSK@3@AEWkO&>o*zfI7vf8QFNqEcs2XHp=1n}ow^_@T=n4N=yjJ*eh1w(qm}}vG_X9wF zfO-m}P9K9TmjkNssDBJ4FxVpaG2>m3HV_R;S4d%Wf}zv_@ki^F7Uj9t&UmYPPNExw7Iss=8#1*k)h3oW`+Z_c{5qe<&8 zk{1N=R^$W5U zf{(Q7@R=lHg=!h5Lb+j+*7lQSM1i&5aU{Z2*iTq2xPgI-DlcPQQo){pNc0Qy0tPKc zGW9(}8DNWTEgdzE`ZVHZ>HC39>p5A^2IHg`JPD!s%U;CTJGYF1!Jb_a@i{ni;CrOE z|4#X9+23=tGjT4!sAvpclXwUb=wPBl)$b&x3#9hJ&$anVXMg+*C4<@MTgaCzd&Hf> zn*&eqd30AZXS(D2i{iSH{DHZm6$PC1PGiedi%zdiXeCQ&k?&C3 zU*4qL(Vc#^6t?4DRi+Y=BJ8gATl3ZrPn!ZU$z9bRwr=hsb&vva`dwUA5=P4JlLl{s zudvCUCx8VeN1?g_Mw0TWMtpRLIHy&1t0w^sR;s+^>CP`Dp}nBIwq%++bR?f}c37=L z>gS)c-dOouN!sOmZz#?Q91n>@%jdi1TcJ#LehhV7NzjFf-ux;82!cEV6KpqVE1`j} zY`ZwaY>Gl}h^LNHmwhR!63KZrB&SRdPW50yA7uc>migdd{#k7WjlB&O$lAkwPFQqH zAOOmfLqE~jgvzDI;=LaCfaWGyZP{b^m(!D;jAT)CIrO4G;dVp}3(=Km*9>&QG(#B* zs3}M@V*ZR+)&0$$?1$6Yw2;Dww1XU!^V7^k#WBA+xU5)N~^BeQO|K%7OB!CT2)h zo#7Fu83(Ch7bK@O>xkRcOv7Rak~=pK*U>!f<3EPv4HH+>TzD7KmM|y9HI{0Hm=^47 z`Q*)K9SeUEiKR{f7l0|?n2Qw*|2iT)(n6^tx~7Eq#s$)HDvu@C*R@Z*xzLdBGQads z7Sf}YYuLN2K@kZU-;CJ7tbldJJ_mXLH{4cnu@HJy$F0t>SiEg8QQ{2DPQjCo z#T_`PU_ODwq_DYW2E=onpF02!*eVYfF%>$SfZrrk8z!CQenSl_vZ=J!y`ti4B%BmW z*(cse>`jGEJ6cw?%D^^;G0PTCQ_vR~* zzbVW(AVQw|-kNMpb>n~QOB6Slk@EgcQrQ3nppC0>g~Sl)JKKFFi@-{Y2a;B!#IF`_ zLqs8cNx?;yiKt$r+#L%zX^C+rdfUng{IsNw1td-8Lszp_7$`3S0>~A&VKkv?fpRFH z(ibtlRnz}|p+Hzmh>8*wJCYjM?nay|KSyu4OWVz>nKDE;r8XRerWE_)?C9%#JaPJS zH27bA>Sjpd7NP4fIq15vLo#r!C1aUw$B54&6$_cXTb=>a{7S{uYpu8*DN{p<^!}Bz z&bm%E)L;1`66?t_6NQ+3INtR|^!iI%3_0=M?YI_U8fiF=4f$xu6n`{VKb&B+a+K!Z z6++E&f36^SAW8l@NsG~rG}Pn+U(U6lbJ!Nj7Wo8k7hdWth>G^HXGAWwDCR|DDdVH5 z#2}$yy5GzJt6cAtRG@EGU6DP9l$oH;;7wF#^;S2pPU~>r+jtgSZ~0uekT#e3b8&&+^S3u4G>gtJ)gt`g zuz60XA5bjjJ2`RkHMx>geI1Jmtge_xag`AL{XShbAR|}s+bH;DPVxP1qbrT3*(&8~ z$KV}JP_g@y&C~D90gU?=6Yg^g%EGlNGM-diTUyM%J2FaE& zrOjMhzH_`zJNzFQA$(cp7NpViz7aowoPltR#m%6SZ{T_N%gRM9#JP*lOy0FS#!A45_R zH6;o`>kFfhJ*y{4o}cr0o&b5u`8-TOIRn@ecO*mY=i4~6h%`+@1|5HAiq884F(KR2`X=~ zSAAn=)dt0ViPg4*U7~rbU;IIp+HjK`QT~mKQg7IRnKxFquOVxWj}a1&4Eu_m<@WRG zpBIpi@n4bx4d@Iit~IAX@MOwC8JPA2uq6uy18!%H?j1Ei_?cY@*VI@q+Wj;cM7vXTrm z^;gFZh_ilPOd(F<9UP8&H#5#%n;u=$DiQ;A*4)6`|Nd44E9rfrl zqUaWrA}>c}Q=znyZtMkbG0Tyt1cJqG6S>jzt}Uoitc>n6C+PHTYGDAW2p19Svrhc- zU*{^&K?KXp=f~)B2=#)SuuHuzYs+T_sRaT?Q7Fm40Vyx%-{1Aw)&g`gYSg;>j!VpF z$zajw6YfTkumgZ1sBWUoSz)?m@V?=wATr zaJkG*@q4*>;M~8^@B~+zQa3VqEn5WmGP!UK8U;BEY;*C)i=aynTBe)S!#t#YNf>L6^80HS?bUI z3Z*fLfqlVI02AUt2G~W~9azn3S-!+*GQ8$Sdr~JoIQ2r;u#{@t{ zwfGOg_w4UI<9p8p-!rVoBm{j%^B4r>pV>V!cF||i?%BtCX7`?jJ$ioGXNZr8S&)=f z7(&HD$|ekE;Day;JgamBbi9O&{LhDA6r5r-ywcP>Qj7v}^a8T@v^=D2q8ySM6zn2s z#LV1MswVbcqA)#b4iQcXm1p~oUrv)uSjQOd&MYkdOx4M17?W{`2`T9C$Y?;dO({7g zFv(as#9C$|DJ*WD}B9HDD1@5LC5->RR!N z>Zuvq>6kk>z6f^l4V6?g!KLQXG_`l~36WIRwQ%uQ(lv+a+lVO}((}vc+qkP3Sjwmw zG7HIh1cdQRtMGc2$!J;d2i9gGre9NLd7| z+ydclKD1ooG^|ip|A-gC5f+Y~&%U6#nX{;Zrj?5~5e+-sJ&;vEmBq1u7ph0hDniep zpk-{sDX7UTC~M;AOQm4L=TpbTFAcz_CFPQORt*6tU@~!iLUt)SUYTcuZu83?jj9U( zn?h1ihegg%UCDoGZBt0ffL%!LnVTbF;9=%bVUzMg%vhsOJUm-DX8V;&CRpCD5~eIXXl%i zUtUq)!lLELWD=|x*DGe98lP6cYZf*-^~uUBLP)@ZR!mLQ$csl*1H!K?6W&_i-q$zu zfk^;nS+mK_tFPz~234_omKf;-6=?LVD2-$B1hrtAaC_v;@wYR{1!bHbyoiJ}Dc77J zv*yRYf0&%av6w_9NJD2EI$}#ji4$}w)eePX)}^G^X^|drqT`ye3bxo zPA+xz;p{8|0Vd^ zYi3L3W3Xw|J8I|u2fNM6icb_;0=@ zh~hduAzX&xh6l{WVWaYXno&r3 zZIHt_H7+(<4Ag<%e-z>lUWz6a)5I8}rV3-XgW3@bqXAx^0p-b=Y5nP;aB0FXDZ-F$ z8W+qD7`yWST-hpKqT~UVUuKn-61^bX%sx7!E+%<$}IF0mOVyP1{myR`P(%occVAp zqo}V6FC7TWU()dd)BUh}=VT5Dk+;ms%DmpotC?rzqpPDz>nF;rVR<;Q$Q{fzxIGWg^p+sDa|OiKoQqdYIs z(&wF4Ja?Nc-;?_<>T+Uj-Qau5%Z`cqgZ~FQZhE!dEF5^NlpZP|8Uer^|L8WBS zt-T_|zmH=A)~6BtF_9qOWd^mbu1;P(n1ZhzH+A&_5y&(iyn}q7OZCOX-aL(Kz>LYd zxPZ&49qAPzzDL;;s2Z3>1ng#Ux~l$EcZ%)$>-u1jjWy_GQX?qY@uEq#u1u>ve*8OL z@!bCHH<747=MARRyxJH2N#&%FfBhjLOx`W6ds%O?_M3=`^^|XJbxdrvo7x?CbI}9n zzE@#lZ8k&ppGoOEp;s7W{J4~trCwJABBsk`ZKlD) z`~A#ZnH~+0*vX6S$$&E{2y{iB6P?(Q9v%Q8Tvi1mDtMc&61X+9OP)rS;|P7}398cQ zi^WygR)l#HT-;0sw9)upWzWJyT%uNPSxTtthhbvOJNLv8WeQan1^8ImQuR1ouJ{Sk z^c0j8-#_Q*CJmKEf%R+hxj#qy1Cmt zbp&CsL`?=m`i_|{(4&9&V_}RmurLkxY4Wo-zrtu8rg=4O+}z>I_%U=(H7F09Lkq+4 z9&>%<#3UR{B9LLZH9$@VEsC_ZHz7W$Q|zm0>z*W-UMac-F^Ux(P-i;Nx>1O zy1a0b^e^VO`Dg*nVd*!<#~c|A2S&I~AL(QNr4kAMMQ0W+JGDwR913d-pNYZ~pKLV^%gSqVC>%1h1FERwPN97-DJK4U-+JMe&+c z#d_K@F}0?gZ-f}TZ)bTvRV<@ukIlC%I2CfZ#4=Fj>K8I)RI;3zV}H$^Lpn`WREDjI z_Lk!tl`Ifp?d4IA=9W`1)S**7$KmEk{m@;GG~sZ8KcaB`{n?$`n_k%wf>n zfdgGB3l@(SgehK|%E$Qz>lpv`8gz+#@s8eiE>$ck{J(l!30{UoRP9uLaOYd|=~a`GU z|DrTvGJOmzz5}ZN@G&RN9?+VW84 zKj68l``qwMG?n-Bds}IM+M%*=d zNy+7KcYA+L8jqytKRX*_%C(vhnhl-MIz4)f#hp2;NSh)EVhpoImS_z+M74~3?L8Z~ zot1ifTHkZzg21ECGDdz=-};7DO8Qi_Vm_&@(uLnzbCiZN-RL_I^!w_K_)ioLTJ|7| ziC+w?WW9Mem(*cxm~qClg7Snuu9B?IWa$EjF`?J1k+)yLak+xy6RsqC?s3Y>7(kqT zdlX71!k+tZeDY|5GRgcZiyD;(2oSSRS)2`KZL5ItWD>zq=Ges=E$RXmhzAq0+Y4NK z)n0{Q#e+W@LF58slutB2h;ZyMf;C*!az4a5+D8C|^_ViO?{6>zszSjAD9`!sW_=~} zdp3@vIJz4p30(ty7GGud=;f|}#8p+CZg1BhH6?P^H(xnH%2Dn;31Mpq5f2HGA|pD2v)umcV7h=?t+5A>~3ovuQtb1N^Zpk=uLM}y#7v- zvbQiD_UPVq>zrUx{@t~Ob z9uZg^1Apy|(AD5V!F~Oc?I7 z$Qis=li5S5uFQqpdT6`mMpEQqDF#Nns>Z#{bGyz!^ya0!q#<9;L<{Xi21?Et1Hmu;a zVp(d{F?H2=eK{V#tGyTUy(!szC2Imh{+r=io4~9^I_0DX ztCc>Hn^6usVK@{IC)TD5izZ>ZU>ijQ#XIg0nP(bg_rOr$%5jR3=tL-}?n35@J&dP0 zw5IZ2Pc=qG3)yHsS*&dt=qhz2s8%F!{cJYzvzlN~oIB4|6u&*8x{+84vtG-!NmqTt z>k%^+K%L$V>US4#ynH0|Dn?8R<#GH?g1u2mkHoYf!}Dgqt$1^^WKpy*ExgzH^;PCv zA3MoD$ip6CLaYe16Yn`xJ`S_EHu1M93+4KX-d{qDQ7~CC2(cpl z5kd~=7cMVh2OO?q@YLAdX_p+6g~`;+;cz62 zSfm12nL6##A);S{kJ9dEuimghK`Y-y7srP*edB5O+Bw9NFe8i`ym zaXu%*+}8#vrPy7Aj7nFeu|TRIPmP|4sh-rwo;0f745{7(jozHl-n_!zy5WX`&EAs7 zUL;jtxl|u%JcxUUPCTuz{#{?=W?%DTUklZ{Hm-M-XO;=xB}Qe%oo5E;zlwo<@5*D} zS+-UTajD<^B6%?Eukr7PGgMAXC5rv-e+lbfz(I_f46GFnY(&Ry;B;}%4R}3$E!&kE zJbWapmj_?y4t{$#c)t0Z{43gj9Hgx-z4;h_=N@|-`u_L3_jSXaG^6hs4xVX}7XVEG ze(W-ITtVn#G3H(=YT6LWC{~&gKfhz;63#HT9}`0X2_LgQxut;ZH&jOH5oXH~*02%w zq7lyi5e`kWJbla$zlH^+M}-?(d~o=K%|@*lx+GKlrME`qsmFA$TNNzFLfyx77zl#l zZ(m$tz=wiW|4^&r0v>J2bi?3!DIdD+-K2!YIOd>BoyHX$6xWozYS2m&I4 z9kxh|G{W5;yh@J!TYBh)>1~;Nc@-JFUszIex=Z}c%`#K9ytR`(P$vv~Iwo8)pHy&{ zz~t)DsBI5{MOm5r6)*c2a*WbG2uyHWQR52`QiXQX8^_TM5rJ|cJC^vc=bt}Kvv zU638*F(sQGhN_1zAk5h4D3(@_?$M_8(@hJD6~sgD@`#;CbY0&DfwSL*>||pOW4FV9 zDRuNEc3Be7P-4VzWB)@=#xhU55lv$6=*ej_eqWGXUfa2TPMjGD{uY_yo&lvXL_HJ& zy}tSY3INBXIe)f=_Sb=V*hNPcI|zv}CEnG_gDBlJ(%Mk#N6fu0JV>r_0VGXtY2g#N zOL1hTQ(N}De^@ec@XV>WJ_gvmCb}S&y6I>$LlX*_4|>Gbc6 z+%)lG4f^n-v-;1dMTSBe;S>iCNktB>=BFjb*HW+6fry5L&)4?9LdK*TT2-XcCBj?t z;^SW-$JPE4J59SeU8vS+LMXdFbHi)r*S$`(@vaHr~Jl8+vuZ{V<^JYyQX+qBCbpcl6N9_?0?j353QUBYcr`^Y9T4VgY=?dLvi4bNl*%xcy z=WZV2qdf?B8Q78n@yX2xd7sHFKOa7xU{zcl=sg@{dodIP&Nef@6-Rul zB5wB!!VL13ilsffMLEx(>+G>UACEYnO#NorKZjp@zCMDRvV=j2dGR@dYFr+Di1(sD zhP@%};`{j(fj=kz;G%dH(jg;-Z)HGDP6KxE;Fz=_Rgq$*erNpn7pBOI{tx zZpqVmfPOi#fYbNy^ih^{`aU9jU3SQePsJMzASZ26t&B$(Ndf$Z`JME)_LU~+I$m0W zPVJ*q$u%5!y%2%@iS>fkCIY>$@-W)BDje$M3F8uj6ICzFxLU>3l0L`9U6a zE%b(@_t}bw~+pWCY$Ho!$QUhJG#Z{?6o$ z7`5EJ)05r6Ka!V)qt2zouJ1|wcJArA?)`0k2EO_kT>3NQ{m-y3KfTz0e%kYorhABd zWf3RG^q>pgrUxg!dRR|?_yPc=^MNy;@NVbu#Lge4%Lwr29|{O)lAmzP<$lis0N?4s zRW^8~d^B@uc+F40*ZIM}cYnYAncHAP)oN1!pZ3jv^{5KOvs*OEVr36niK8fQWQ}SV zJ9$*|`F&3ht|0&n*-ZW;>J;_Cl4M(%As`iba(73GT|RY29TT2PEcl!>HL|ec?zWPr&hWrP<=KR*^)&<>7j}qfFGC_OUJ& z^D#?Y6-JU9``Fk25PaW^8qGSrtgy7$M+pqxfgRfPc1sh{oAQYB63#4oe2zX>S*%`K z_3K3W9t{nb*+j$CLuM@2uHa*dBz#UYi>~SsMsB`tmg_f;Gx;Jfj{o@1J`;RW&jjDb zt?N>q5R>lq#-00GtK)37)#m+^=T>jP_v7u&pD%WYFWk~D;4R*VQ`vmZgQnoTw6Q{+ z8td&4J7N#qw)uz*slAx(0Y5gIoj<<>SC`*9f3a@xkGeV_N_ZPJ82$(C$7bnl>67iB z%Ewu`Ut2;~@@Pbc{};i>)p4bOEA+n!zHR_1_O&8}ViWma1Yhg0xUv7W61jbrk20lu z)<GY#Q+V^4;KO*!!LFTf#eDKf?784PSMKglrnUl3_*|xx zPTSKDgbZH5?flaD7STM^sGwR;E%6#=z#~$%G^NepiI1-L_51)IPS2s5sr*s8-SCTQ zoRPK_Ab>r~Y%^126=J4!VxYkdMG)H%$+%=)U|@IA4`D3CX2D->dz!dP5O-DCz1DJF zbX%?HvcQv41Fag*p0`_OGmDs*c@7s}SOhT<--&=W6mfeT*Sm}3Jh+9aQwx0`y$XyJk>7rQUuc&4 zfbWqMGZ;zL-A(YOmF&YSjsEMSHCffG_X*XjdA^=4P$U%B&4HwqA>qPj{$Ma?+kG=l zQqLZ(N_tjDtKfsIF14|}lJp`ncU)I9=tBFG^43x=Gbh{XDQsqDqEx1~ z)VcTX?XO0)zl-^I_ci2yX}o2&40c~Y)}Fr<-Ubp@+ODvgLO*!}%*ZR}&?OL06hpfw zG59yTAg#3~NQrJ-yZRos)k7`mpl-ZSB^=K)cyu}iiNP46jxkNIkRC3Nl5;%-GS-K+ zBbm|UHC5ZaA6PPCo6tDtqc4dWX*qkay+f!{hzjhKqNN#_#}%9LP?uJ;;g@+IAy3BrpS>o;rffjuHF&&S}nMv3Ja7Ns|Zc8?G=tCK+`HJ z(wx~>agy0%F~U70Q)E=3MY&0Jf+_4RR73Q- zFV<0k5-YBfTu<&5QEZnvF{#u)f*i@B(Vv&5GhKhc(oI=ITEB53oIKQMS4$A zP;cDv=Y|iMnGME<4WW6;V-Cq9V7lNouJm7mF%f@Iw2gBPF}A{HDBe^k%Eb!iJQmbE z7`mcF6E84m&`)BMD_{V^_An)(?24)_S>^m=UQWVC+vmtMR$VLxqGAw@B*i>Us&Gl^ z7~6b(4^Y6?Fr>)=i^LX*8Qbq)W!?r@4opfTO<77teaQxmb{mT7ipLo6SL1+tr=_wB zm#Z_|i^h-*hIM6C0K}mRtW!C8kvHN%630t^^`3OifGWGcbvf}!eSq*@ldGpaeU-Y} z>tkX7Zt)25Yff2%0)Je2mPXqfwWaWT&m81F6JKTs<>>hGQ`Oe3+r!q?d#8ntGBpkm zCBA;*gXvuh3KSjo=^+Mts68E@fkRQSB|eT@#N$fyR5eF+DMfV`yNFuVouXc>$rqn# z_>%_(kZN`J{!{x4#Muijs@YFE(1%??!n_RK{i8+sesCB|NBb0W7fTwk5r z6W(BdUP70_Vbwma(iI#RC-7olxA>uxbBe|*EEJL6JU-HuK>a;R^-3d(oRNju=t}Qp z@cQNFO2XIds{RvGOG&YvEI$4qwSvT*cUWRf!u+u@bP%lBHqpLd8j#;2s&UFCC$iOZ ziW+ePoS;1{&(K0dJ~+?qrmn7EoizIEF-wgREO*e7p5s2ZcIH75 z=ELoqr-D7>Rgz=H*`x-tEpQ|gq`QdM-W`smS*}78d#U6`J=UP+8)G|84jfMXDQVo) zw~MJOHdQeXUMD&i$KNLuP*v>fF43^M^o{!QAc^f1+-)(9xyP%X(SRA08*mx3s^+fr zzu0^0psM?||98=g?nb1$yIu4mrMtUDL>i-W|B-uK@7 zdG@n^`vHbEz#?Dm{Ys^*v2M)Au$V}xR&W35ffc@) z*T_%CfWt~Hoo0{Z-o20eu6>F4gzFOdM;5ClmR1Nq{mia;IvKTw(1u^8_-31;h|#dZ zO_Mh_sg5u60zW%jAtZd_xzR9_&_!q5IG=75)iD= zN601+R2K+Z00bNlLC=L?)IczMAXw87> zXxCeImMF@Bp$SP*|2kkVVpc&WaRs4Y#mL|OQ8tT2CdJoB+(}pZ- znHOvVRj~|BNX@XJCdvYdXkhwXB|~2&LmQsMI+=s9+x1$z66($%vCj5Hr5A1)CeyuE zlli@lf#J1XmGsMC=^oz}ZfK1Z=Fr|i-NQRs86t}0HzF2BrE_e2_4M?T)6AmIav+EB zO~W`U4gO?4v3!4qK})0>ZKjV#L-bBkkkkTEXE5t6!h%Q42mWYc%FxF)St%;K;!EPC zDvkA%?C%#FU$D1pEoINL(yRH2JJGYc(ZN-H7YsojGtPD$EU1Bazr(h@o(b?AAhsnc}$K~Bx0|JIsa>`S$#fQSTYM%)R&wn92x8mb4)pL#dva3qL5p7)xhoSYhW0Fs5IhpFFnMnS z?R8QW{LsXphwx&hO?uV3--4 z)aViu!Xs7>gXm~c@f%apN8~8(6TEpXp?B(_{X|l%?&@vc8@)Llc3x9--`=+Zf$bX} z?Qt&Ese{YAh|JQZWqZ~`kHePVJ9Ox~7Dp%4M9(b3HK(Pm8OQWyVz;Ucgx_dac&-R4 zb<#?UBuN^k&R}!UuR5r#rk3iZZ_&H#!wjCU;^3pVGprJn#zyfMWi`*%mMj;f#pGin z;6k;ALOCmBL(E15X-k8%13UVL)v3bQK4ga9`qigdu*?_nB0S>^ z5gZCBooanxv^k~np#%!<6>T3Dj6*Rw1u=<^tYRl{MZ3h+ukmtTECnWm$sAV90~w9k z=XP>8umz1a1ghrJhR2#Kkc`3WX`4QL$b)A(@E(`$HVc+FUzGRdDt3t9rx`V>z1`S= zn$kq;;xXMDQ5 z+#D<=Oss$z94ZgdK75{g+p#X0yDGmq@}Y#C6k?FKGp8%q{a(4zsmA2y<2;q5IS#{btmN>fmeiNI*VLH!x-h!}1cbASQH=5(p+z5NsBc1}E zKI}puQ9-#<5Htkes1)7XYH*EPqHIF!eP_lH=B+zAogFH0VV(kEIrlJTI~}?;z>INU zBN)X#J}cdE+DtSs;h~c+ZPnz}UUMNdhpP*+W7aJO$R0VXrqR3-U-xu-3a%zjSAl0evgh6*mPyL4KGtg&a`DxZyU zU19GJX{DdGG|1}~)D_1AIoxE3f&OeP7RA6(Ljyr+fzSgn`K`~L4ZV$4VLsc$V)*UQ zfvxAO7d0T!`!2dO3cOnu`U|rs>^gSFZ0xt&#FG)@x{LGjtB1iuJ)a{z%-FrYRA;+R zcnoO-mliy|jtjKIjAl?uYzX0bX9Bk?F}=UvF8+?2UtSv@Z-r3qW!$szf}ppMS1r?O&y2GiQ?e+ zeF+9W$NtOL76fk(U{bHY)tciYHJMhoc4rrf3RtUTfz6b;yy0?PlyY5C|Fwc|v%=@H8>E0%r&w0p)N~#3Wf~ZppbH7_%@X_zrVNl zexzpiq5rZ^*kL7Tq5Ao`W@D_d+iGMcGwa1}pv!cUg=|-jb(EV*uu2ZO3zjdxq$bL2O7s}dv{vNMs z8b%RywZT$Uzm+~FltTslF36a7DxYbgk?d{VlF{%GI-P?@jbe`)@us= z3tiV3#6z)i|HhwA0+4Rxz6v$LE$jL8XQK}4AyCvVyQR@9b7Fb$L&|Lm{RW4h%h!w{ zL%;(N`p!OqPknsI=kZ@IRN(XH2iMm%e`x#vap z4xB=P@F2BT^~wHl@@jV7sQ&j)50Jw|Rb9-bBsnh*^wzp#f=o<8Ei68H)%F92yit|& zuckRijk_nU^OdeR}c4V!1Zr@=-J_O8u3Ydcj%;N?wJPdrp9k}=?aOrX2Tl2toPXd=;1g^XcT+I($ zs}Ef73*49s-24zo{Qgtm2YBGtVL&2o&<=OduHr*_bnx${G~KUb<&+>{&}T%}-%V+t zBVAWtU)R{ItYb<}&t+_EL{7(vfJs71$4N%VX>4Rz-_%lFQ}aj`s;XQCVe0>CF7x^xSN7OUv`;p5YPUcCJsAviY+WDywU2>*}yc>C3C@>|CFr;XkOUsaDlBpPZR{-9MO+5Wl*%(1>8vv`E|= zk%W1%=yBk;DVegYkPQsEF~Nk?Kx3K0p$r5j;1QKY!X^{4jC;SeomNo&erKOwKmY}o zeE!`k3y%;fEt{yUI=^}R=PzGomsWs-@7$s?8(X`g)(NYdA25k&>FDWFb4zMky3am+ z0_xKyrEAj*Z%vDqLQVR%501?$H=|$~z|Rei&n&HN0@vhinvP{0;^A<(q*HqD(0F!H zrCrTN04&eu)rd)Yzob{i_3bSzt5DE3x$X6^uuW<~McwZHq2iNtFXQUy%<`j;pAuhH z`x~@-zK9lnT5MXo-#0o5%Xrn)(JNt_R9MweR@VaDmp4+59auh4bV-5+*V~uO1ASw~ z#J;%XoX$79%j;Wh-LK=*a$m$G8^PK}re?>c=SyoEfF3n)%zf+Y*Tvn_M3cGVq1ES+ zX^j(`z!`MCkixLowDRgUN;VPT0D5HknEm4%@6b4n?CJ0K_jN5DCAF*@j4QpD@);pd7$I2ITOnYkimgyAp`)!ZJO!5Ra3Vd2?FceE z;8;18*U@$q4aqgO(R#SUj!m39!)y#kn}|{zj~AM1yuiC?eP*^&tKCGi2in?<5~!?u zFgX&(y(B18!i;Iji(eT2{NV%7bi| zrc~7&_fb~nsDf$7!&g2Bm4|r&*T;wX!KiFU1>q!*rnJit^8Fd zE4b0$8p0l-f6LSfPLE_esVGTzI;pHEt2(KwX*)ToZWx8Loz}Fxb2_c$yHT zt?x%=|JX20;{363oT>U_)3ng($L4tj_Oq5HJ?FF56|b>j$hy&zYg>0HQeEr!jjJfx zo_NX%4$v^c8?KW&rzx3);p!R|^*x|W(fOf z*Q*ZYwbyGd?Pu5P?qi%c8=lLqH=90(wKwkrZs2D(A1q={Ic4C8vklwGdFwjc(NCD= z<#DU89xGr7yY058`&TF*e0kf=-5&p}j)thn+gJX$qP*_=Nlp9t_tS8gKtcU-+TkiFRgKYF35b49j@WO*p zc`X!)$oktvibFI*QIWBW6LX>Nq5iB9(3S?6HkLX)e2B(`k9KgkW{BpZU|a%=U@&r8 zg_hdW5}jW}79#;E5~Ki3Io4phh@^ddgp00(+H7N*h(IfmC;M|e;}jyrvO@`9)8_>D_+qL<=$P2r=R}|B zV(Oa;7Cz|&I@$`w|nO3OUD=%iR zU6qNE$2A2X0+ zE5{1NV3vF&rnexV%hp0?>tgWAFgA#xBWN~=im#~4oT;%Bo-zzJZELpXtdU`oq4uu1 z@^_ojG*j>I>rYoy+^TWVVRj}dfR8RR@;P!iM8vFbe!p(-$3CCv&>`5wxak;ItMka1 z+Bguq>6}lf^DI}{JTbcITA8WyYM?_u_acXf6)(K&u>8$h?Ds zB`IW#v+)x0Ib2!w@#KlleM?>o_M9%n`pXAs96nHyw)G{Q-a-|>9l%R$2xnH^#xTAe zB%5uB6rSG3@xL9S0h-c^@j3KV(lmbVh`KQl-~tUTiUjP0Qh5uBHXs;F$PY|Z z1Hm#IAHodgiK>(eX(e94)!noRqig9$kSt((fZ7mDbq7Hs1Vb2i=Sh$?IuVdXWDs~X zlz2S9AyO8AkSloXI3IhYVcFMRBIVB82`eUJKP3SnfHdsIA2nh7zJHdFv}G?}L^~hA z)KY}`3d&F8Hy`U|L*7M&jAQ^o^xzpRqUUsMyFfr=G8iKG2nv&9&R&RC9W=75L6n0* zQ2FtsvFPUQp~)ef)F5eWF`iIL8cRGh4N&>RN~gAs0bH>AQ&M%wj|ycWT!G_|=2xZ} z$aoah%Wf7B&_BNE!v|p@J^oFq0G$G`3b6_Yp7K$!ivn~?#v=59OPq{Vgq%%;lv(fr zr#L(L)R6*CD9I{^bf1)B&S4L2#X067yM zn4E=-fg7Fh;X@uN3N|rfMt)>$at2O0Oj0^pUMX@mp{?B=3RV#kCP7?s1}bJgDi#4u zN>2c3I%D z9wmn;(L;7327YEZ9O6m< zu>(A>rfbT|uSQ18SzTRgX_3t*wosYmYrW%kgsQA*)uQ-ATh)` zoRU>YLd`@~%OEl`N=;2&%r*s|pZ&3(DOAHySV3D^;<=`gHN+BFo=zpS95u!qRXW9^s%9}qP{JU zkPbgYMLwX4T|}0cUrEo>iBHf_R#skI*+3?!K{2Eep%sCZOMYi(8=qO6h?i@3Z?3<;H}Z)7@D#8=$liG+eW51%fdZ{+IQnyXI;$^afD zx)*~%6d$ThO((&v<}4tgi^nMTfK6D~BFl7#b{RR7=brtja8YG?D|oR5+KGD24i@TN~2Al0tc)8z*1sb6pU{v_4z_D>%G zQhli2^B7)vfK+d(F_2a* zb`vG8k9J=|P#sN!#Lt-bk|vIebP%CJ6IsZV54QJGgUFTk)27fD7yS&p$f+anVlH9) zX6cTrh$yu4NvZg+EDmzq#gOH5JCyM zVqUdxU2omaefMOh!rPu_1h|RSmj72$eb0%&3-KI6>&S@rA2hg;()=`7j@}d12X`a< zJh|@1i8`yueSfvYFaKD(U8ny3dgI@cYD=xh0^e1;snXB8n@@1KQp`IU8w7||p(;DA}}yJ<|fQtiweZ4OSso5jseaeG$&0T8N=PK1kAa z5y2B*h$YyDSjp;2|IBzCdE86Zdbnl_!RJVS#Ldg_LEqnx@7_ zKlX^MruFkv;jwH?G=3E=&zUU;ngUJ)7YM2>(~Y%;&hU>J!NziOVn z=Zj056b>Op&Fsrm8M!}6Rg2MJe4f3M4=Rs1X4C8$OK375g4VlXd621dl6H+)*Hh)RhA}l9sq8li+H?}HTY$HQoVx6< zs+-=4n#sFj7FZ*{h0k7>kH&D?R)Vy-4}?I)f{470N^}7pdB9)$siTsj32R`fi6=W*LRGrZd$VGI`f%pn_O~n2{T@zlfI?i-nATf+}-qJ6F8vMbEx*oZ~e#n+u8Ql zH#47tR8Z%yQA_)7E_Xx5kSCaxq6fSOcl|l3*e88Dh8Hhm=@q|CBV~A~VVqyY_}}f) z9I6pkX&@zkz?=<&pNovj)+IBkHpOu)kLRhV1C9AYRD11j#H}!TMxHnOynQ11l%er7 z%R73~q^Bwxc~@oPy@?)tdyDeI&*OBuP7KPivL*8pYy9s|EpWS6#?-Hyyh#xm-FDSK z1<<`nnQBeI@>@!ETW)|v)4`m@H{+0H8U}Kg@9w)lXe4{L7TmX;kRRte@^rS`7V_i%w;|FK3ViTdyVPKv?Hb9pZ0+X#IL(*ZTa~}&R)G) zd!SDl|9x4IdeRHR&%Op@FMciuhx z`*dE1F!_WQhlHA!2NPe0911`0z46Gqam&5H6CB6y$Md5>z{2|MFHXyIHtMx|sHhM| zT!dohZL4kB0G&a5fy5I2ku;p`HrQP-LeD26Oq)oQNOjm6fGy2&q(-x<380YJyrw)#{Iphw{^pLcQAMS|1R^&5 z0Wlq}bP{O{3=S0{V})ULzN8^frV~wOFid9hO=ihTX6sDW=L=9PcAh5qWvA-{F6BPpH{X79I%wTu#<<c=Ir)`s&D$^=ya#fbeGk1w+W$E-3R?&(>)C{ynHi!vNA#k z5&c#(g1-HF(-$h58E%+aZUcKL8iCxI6gy#}=K$iM0WpCPQ!U(HW`UpfV}*f0rVVKA zrJ<<>XrUV502nR^hNxGWSvZff*?{t59_=|SJvlwo3?FL|gbjlEzY}qkXb^W&-%iV1Z~)M551w_tvX3 zHwHCJV}clvZ+#wA8x2$uo{VyXJbM~si$-yeEmTK$lph7C>CH~@$Hd~n$Ybtk-z-oV zAo(@d`KALXo(15#7_=vND(GuD76^#JFtoTWGzSo7g(D&%1qsImINSm)kq5~Y58SJl zYcP-@0?B&HVupb5cNND2;e){cRmCx>*yu%7K*Jb-lanwDlCg=9vx@xIatT1u0U-x0 z9dL3&27bW9acQ_QiD}3gxB>m9<9kHPDg-DxIh!ac6F((~7@*%wJW#-*aVZ!8@dnf# zP;o$g=>(*KH99~dg-^u<7&|c&Kj82T9EzOcia=P!C8+|aIH1#jpHr|33dw1p5j+5s zv(ocJ00{>a9f^pZf{~AsRTz--?Varh%shxVlz^_&bI1Z}&B~*OMa@CYCP2y}Ld79U z$u5FQ!U${y0)(8NQ;v*T5U_L-T6Vi^|Oq7R7o0~SFbHY1{D z;}X(l6;Y&PQ(zO3W#m%E27H@E;32a#n2d=Mnr30*)>3{>sYfnX;jsv}LfGz6Idh3|z90EW;?- z#IdQ^0r4iI<=_(3VilGnpyzpH6$a?NsBMaGWEwDf06ZBmVZg3=1vO-B!vX&%VPFSj zn2bjlkZr)U0mlY4fdHdMY)2yGQwDSzFl|7&0sUr{HU_2=Ji>2m-!tUr4K_?&U#Cv zlY!8PG1gzzaX-z#u5v%!#OruJ!y=OPAoBqu#s0K%2bM-$Elct(4!P(XQ{{QL$Z`*4hJ@p3`wD^>*}e+3RC|B5qJmzhn44D+9K4 zW_(qZ1z~23oc`lFINNS4Jvqy1E$Y3mHWA|I*wcDgFUDV?(GRK|y$gY`roV+ooUXPe z{*F{@UZ-d6PTPp*9Y_mG=bcAo&N^u)PBGyM{;!QS2&6`UA^BOIKIHY?_35WR(6a3T z#17fzVgSrsb1}$o)qgR>rK?GVjmPfvNwG-p&Y>FRX$_#_xXMq*w|0KOCU^=}|3zrz zVv8d7M`*-(H7`f%dbI!rLZdgT!e>{D8jAlM8ktur{}~#2`>UVIw>UvIDh4qi2(KP!ehxDA#%dIbO^q<^+ zU9tbSD*oxK@?BFQ;v3Pc8=+q+F8LTvll>4hgA|WIaS;qwEkGn4hpet3a=do1u%KH> zMN|Hz;svO};{!N;zf|0^i;796(zE!tirZE5+uBJ-V*3m=k97D{sICzD4^mDgo4e#RQw-9que8x4WTy^v-34Yul%YWNF1V*Be@JCqc3bI z6)D2!!sUwd-FXp#&`9G3R#?F2iz)-Cc%;}>AznfS_#5j&tWm0{WzXML9J>J2V&_nEO#KwwtY{@pf$PQ)4m_4)t{p(jZ z>bM=%y`&j}4HOho-jBx$B!my~r8r8W+sch^}{GsCfO2PZr zUkZpU&kPlR7#cSU;$k_T>#pu^yu@(k@d_;M=~8+BcNJGZ^&9S`vaC^Qt(IAT?-ku> zixDK+WWLyV(+9!>Q8jUFsjVV-TDsSd{7> z9p$%isCrX!#`GQ&`&T+2`BR)(MAH~HX}*K(ij?Iy5iiH*)1HC3lG>)1W$ZGi9e%0! z^np@H0j@CQM6HYRR{5kSahVtbJfnU^w z&z0b@-_bjxrdA@bg7dcpBMl{^EaC!40e;BP{C5zjz=yp^GtL2HX)ESW-uzusq63M6 zju9DuM?XO5BV!v0fP<)AijWmdC$aa#_O|l#e8`hm5WAR1u2~S92(|PnG5b^r`&4P$ z7*Y3p&%iJ~r)2Ypinz4A>ziwrr;#QKFj@O(Ir~_k5hQH=QpEbDj9rW@@M#|->X0U4 z4bzT_x2srB&npUhnVw(ObbEVqb91fe7!EKOz+!)(u7Z0m00Jf&v2y-Z0D1se0YD8v zD3Z?Ua_+AHFnMGd`p7a|A)pFi5C9k@oiZTS5r!(!0E_^9Astu;kPZ+TJhBS4S5KFH z(I{;d3}BRuRVctF07pYZ8h|9iKP)CNECxUoAS?(9k5dS31ZW6=CLq}X!WW=V1wc?p zbRqyU0Kb%1Q~>b}5X}Gq4UpXc%mP%l{z!R%L<5L#c7AQ_G(Q)XNbN@|A>Hokw$NydQ^B?l2ceT}j9Q`a-oBt90>`wi~ zn;+)-0N(sF`uX3Nlz#K3pRRNa3yENeDPzgeU(t`lZi2``#b43Szbq-)>M;Kc-n2<~ zJjinRT~hkRn?OnFFxT_lzbYyH5&cx?p@13&ihe~uB|j!0l_d-YS3{+_UMI)phl~hS z+4%8JPO><;e=8|HbA*F{lG6Kc(zS?e_`0Ya|3OK~uKKKP;}>skMY5lF?4>*Z;?3&w zu8(b}=iL{h?4NqB-Z_8jy*;S@^e1nkaa{Bxlm3l2vFH`#hVT??2yh9aZe>Qs4F@!l zKxDyBeb57dk`g^<@B%gi(hahzNXfACb{kY}JGXkiIQ z_J8Ef-zB9F&WbCTbqEj)6hjb*(ndQ&@n4se{uOV+6uG|b`8^L#1~WZ{d^^bXKL2)D z5XB`XLqrwcf8>K7{I`;l>;%M&df1JCuw|W^99(ho-%CoRyle(~lL+K~He zJXCz7|5j2ee=hysN=mXql#UG;QeFt^AEiFKSe+GM?_fj7m*^< zg*g9IQi2ZCQT)#(C3VuK@sSm|!Z-`8VzM#l=zqYQpI-)JmC*cEQu>QG|8+^}U-IUE zP*VCG{iyyZD9GBOKyb$aNfJW-A^Q1e-c&6YTb`Kp>iY8PBEDRrxFy1uuO8$2S4nAt zVh%bf9dAdoOVtlW0|gJ@-pf(b^s_|Fq9FesPf7jiGy`8C8l?2!xB%+-32OTZYP|=w z-BSuH1FaEqVHI{^X;3>H)P7Gb1Z5S3ge9Z`eOW4DB@Pi8#4h+l0Xb?xMHYT3gibiS zAcT=q2&)$!7?tQ77K7M!pPHFXMMEDD5r<9kFgPxWiBFP-UnVvY1}Z&y?icthAQVhM z4eUGi4vq?pjQ92rdL9%3YPowLq>O-wg4hH14UGv3i+Ji63~GaeI_|NFsDi_zBBP>$ zBcdrqR0WMakT6O7UxX$krG&;OgPMM(X63qi1yTwr!BWy}oZbDyV^cD+@W|=S~N^t_h-+Y-Jjk6ynjf?_#);dpM-o`S{g8Yfu*KT zPEG0=nG!!>CKrG{^Y%4ye5PY!ZR_Za_!{mT7#x$9_Z9vVq3KppRRf}^Zfrf-hc zaEVxS6q%I8z|8i5RlqMOq@=cmj9r{gP(CU)-q_rdm_an@= zz(D`=2$+PLG0KzD$hni_`#XfzZ=ilSsO&r@;pM`cH;f|Cy7pdB#-8igiOJNLq|Hg;Gn!_q$ zb90kM(W<7V=JVxehRo^EBe+z@F=G7U)|ank8|SS%pD7!Uahq?cD)&+Ci$})BQGHuQ zBf7eJdb4w1nZAc-EuW1Ye*uT}6&>9y-ovpv;5a?sTztbTCf5*WP-~6>PJi661n3S54lcMo8|f^ zSS7IavU)G4C$mmf z=8Kf*Im9WSJ(q4x^ADobzi?-3{QL&~uDaL$!?}Fln2WNB#M_T->B3$(hL;9kmmgG( zM8A>%W3Im?U2}M^rkJ5xu_}cr!&m3g1cN{fO~VNS?|iK3L{DzzUy37ECc#wjMClVEkh6-Dp*Wo- zDQYC&7!oxvMHrI|%qnfuw2jDZ)6LzEcay9`kBhS?lqUAGE!%v{GKH!PnR1?VP1wA8 zb`W#;DnKU7KG*F0*q#n7DvgZOHBw=ht576*RP0f<%JM2u0pqyDPw%9nRL5?uvLM&( z#5OtK34^)BCYhq5(yM4~zpNn-zE)Y)*fx1wQ4_=vRft6X-TLLf?KC$_i-hD9F8>oQ zw67BAtaSbz7Y6AHQJ6A0mfX3QnC6J)rStr}=r}bz%FvzuSzDUm6~8=Bkg-{UFtho+-wFnzag z`}2DGz&;{yGZ)=^1@Ti5=R{9m2s<(V+*+FzY!3wq19J1xID%@F29@n4&(&d@8UGqjspO1MZ2syr57|AJ06NX^o=+!0r}F)Id`tHX)D%7*7q6 z^iit11LG;$g+x>-e4r_!Y%F`N0W?Jprh~bFriiIm8~NHrBr`uXfD5v5&o9Cxe|4G< zBL-*zT#yrx;f4X@sjg}kb)eHcgfhembeb2G9{`s zS>!AC6B682cMW!+V@#I?kTFo4D&sv_<)mILZt^Fw;3gX-4kIyk zY{5xQuv?`Hg)|7|%}zLblu|t*c-u&P9QX%Ps0tzqQ<#}X69ic#IzYZ)zN=sY6@8ly zkU#)wX_N`7HB5Q~d#95@kCIMXlZ6TnZZ5yI0igtuFBQ`DBgzXpX=Z#^DZE~) zP?QIWq?}BZ3q8l}NDbFONJ7syx~kr43Q>?$e)lrev((`MB9+OcUTc?Nt#ewa$p?(( zZ0i2n*SYK%*A$4azY|xfw+36Fp>@(a>SOoAio9v*u(s zoWoc~l<05f0&_Yjs;s@q)J9aPXI1mex!beu&3>!p?)a~6-sBo9 zfh0FQQ*^W*DVWoi2|CCNfuH<$F&Dp2ws(#uf8w(JvCMUwfeA-x2<|LcK|mAf`5EC# zia}*jNJ55pl+e(4(QbC#C0yP#;~u%~tZnX;*-3EA6Lp69;m%5==Zd&CR)5;6)yjKB zz|T3}mP)_(gd~Gt_UVLy#`Ydp`!EFw2~5((l- z{B6=;wkf^+E{gS8G1c_EG_3rjX8U9%P4eAG4}g~JS8w13%&6&tca|~W{;k=698cAa zJRC)c;-_45aO65|THD|}P?(}F zG1n~3%F_-aH*em?C3==RLV}IfzrX94ZLRZGJ2m_AeYvFHtx_%UJ-lqKh9*HTI?kk4 zC`0zm>z}PH<($C|`Z;S|cBsuU31%1%{p;P$yqaY=mUB>5He3{hK{W{RO6ET{SM-8= zcCnxM?PfoyKk#a|cmF6z^JC09k3Ff>Vv{7_a~-YRZGbS3-VWLCJwkNHFths8==C2v zFK(G!zXqB;XSNp!8^7E4VDbk$qnD0`l*;6}#%nHeRj;avqEBbc95pQ|U zl@#jh?xyROy5}Q9m9y7v-LDRI`$L~JyR8ylb)PDl`K{_2TQ^k)dY6YX?UmTNDpJ#{OH8zfMKe>**O`!N*F^`%XMt9$SeZbC)y32D90 zJC$4_kB2op^iMQjGL!B}kbY+YeFkP=h!l!ZqbwzO3DBb=!oruw^BMVfZxVyfkP75@ z%6Jn3Rg1n>=ihL$Bz^yA{o#jBR3O|HN&bi4npty4{XPqwC8oxB2wpzVcOn=(oYBV; zU&R3Out4*iJnRef3$xW*L9hNxG-qb4vJ3D845y_ZbC$=kg83Q#3OH>GvqQt)cixe( zBgBO{NQ0PTPd_NfGsreA==?3nibf065aiL1!C^t_4Z;B8Oc)I+IUcqe4E@&g#UmaJ zb_YaNcQo=~jhX_?xcM+v6i`lvmXwIc9GcTtJLi*Nw0ID5x;y4ecg(E(=4f_cs zjE)wyA1$E22q7Ovyzaw+3XbT$29qASwdlpAXyE#QFjIoj?&sa!W?+ywz^3LSM|tAy z=CS(w!9E%o@FP%zMa1klWWm7yg#kyX17pO6`aYE2%<@GXo<;!-Jq@hxjfczTs1^td zT>yb2q3Q$4h_!H#rMuV53LodH4!?4H+@%|^9Ssau)bT?D4splJ^9I=L78s`!8&ZJf za{<cPxRoyC?-o;uuuc_ zBge9E@cFoX8%^o6i_|hiU!TV|SiuRhh*L1csDvPHT4d(*r#8SakjT@t9Wkyo&}Zkd zbXVeySY1pim2(!8&Rc`dm}5VqVP9n69of9F{q{J?2hEBGO~5fGEfbs!0iUs;Gc_bH z>}2#Qq?T%6lr^B2H=r+SU<_C!Avt0ID^#C}#E~9jjt1urLgPbLaTYsq%lad8C!FVQ zvxekCZQv;BgH8UuH~z{j(cTSUK4?HuLqZV^dITQ!CttJ!5sV^;_HAYO*Glksk790_+Q(v^n>J#sVyG1rBC57CE#4tXzOq717v`)m(s`bAg3P9wBt|N(D8q zfFX}sK2K&@uL2!gugHp1@x^Tf1Dw@tk5~us#4pS4m7yV0By)(Q^3$hd1`Nu|*L2yW zWdW5a*x&nK&>#9vq1iVr8*^#+h@1q*!wMx0OSP7LWS zDbL|zq26qs3^zrVq^4>o}-6?to3JN+dx`=tr7N`<1nkFGr!%ga@l ztLi2_m)<&2kCtVxp}e^$%g?U9v9Le|X_Sg7F;&_5WQVisR@$AEBMKL{u9azIRL>ec z9RsPxVm$7{sA0XRFv~DUT2`Sscz#l5^U%RSz@z%kr{W;ib+unhQ@55Lin0=`-AYss zS8|VIvXS(_x&s9ruD!bRt5~(b{%E9ZJZ3hD;+%lWwM2u{3<`X-)_^kwES-9S;IH)X zqHgBEj1;q8zzTZ=hK=z9hb9hzPP~c1xQWTXi6y6r@f2;x0%!5c6e`%5K~#nu=gkDS zi`}Sln~HR6ifx=1ahbQk{=(BDuF<04-vZ5PQSNS0jca+=@4L>_+`ooK((O(m&WY9T zu=iZ&y2=IwGwcsF5eP*YkZH4Ar>78f)2fCJR5^S$s%eOAWr%1d6|!p}HZwyp@x`oD z+s`sJHb@+6b#|_jh^)%}T9v38 z^gmbWRa7~Ya_RT_D?k^+LslamJCAjN2TGz?1jZa5bi*zsgm%LM3KE?59HaCiM7A}f zZaus;SEC+xyfge`UaEZQo@0I+ym-xHK{dP|zKn&c@=7g?!bQiUKXN{W=Z?pls9r9P z!#22Y2`5r}xJhASX}J^UMM~Kl6NrRhH&tj}JWnkDWSOcwYr+3&>nx+%Y};)M!JVKj zR=maCU5i7};#ypb6?bWIr#MB5yA=&m++Bma6qg`5>HB_X?|o#9{7B%=b6v@=BxA0* zq<*#!FI-AhJPlhbN!AFD^fyX2_>LTgy>DqB8Q>J02Sm1y4!+MH={6WO;6h+B8SHN# zj%pum@#Rj~9G%9LnLZiy)EpZ>kzZ^d;lP()c^XyDA6+*X8WSG>c_O=qIo^~tUOzf? z@-)2sG(IZKbBQ?;NHcyTJh+=Rk&LPMXFj5~YK&vz!+-cwLy5ZE^@@?6eDKI`)|Ev`K4PBKLoI_p^>sZ=>|M#e&QKid#7 zrCHfOm|8B%8BlX{73y$Jdug1;iN$i^Sbtf^vPIxhB}*_V)=Di)@K?i?sm1x0YH;k7@{6Se_6v-t!%*HSVUIGDp`ccIJp-s`I^W8@q6X9y?ywy=(RqN)m7-) z8byuC`j~^kFHvj!pLgFj0;|bM~g8*Af|Pj11h&n==J0 z(Jg=-qObT0{fj(D5}0Xx>($E^!OA-4xO|b}wloPLO6;~N_mZ&DI>Wh)nBz7##||CI zwycpHO7;$o+`N*%eDl@L{PLVSSdPwUH=tqaqiDT8MJqRW*PDCI24T^}pMOt^Bi_p3 zQ>Q3i$DS@Wnb6rDECiv?usH+$cOR@=Agz1Z`<9|gh+%Yn7qZa5SyqmX^z zoQ!NdexQ%I5g#kVD0*n1d5}tR_#1!!`?zEz_)tq~&n;;^4=gilaFh_cQ{pI1+Ii$a zyHoXYL``w5a(&pqD(%Oz*(|ybsXP8ad)Nt)k8~}@pcAf|mOmS|X zv`|b=#~zm%oicNuEWVroJ5NO{fWv2}k25D*XOc}uXY|}F2eDGvwP$?X8)p=f9przw z+@`M`&-(oSfRqUjL5IncOa z=knD3swW?WNsznpU*;|e7R$KvW8_3>H zcNoySZK<o2+gub>;QZzO>z|#(YLRZkhw$7#>8c_TT@Rpw-JEI> z#5a&$gtbC35i@_txW-`F#2(H%q-W-#=8ce>=wrDUq)AnXGxxD>=Dxj4u>R$-jpnh( zSg_CdDZl=5uuJHv<0<#gBN(rLJV3%r?75t4biVp=aP?{l+Qm1p{+yb0yul_!DEiWX z^SlS;ugrPzB{)5C5_Bhj`hz35E(Q&!d5L%d1cSG%5OK{BtEjFdDdGOLKTmE-MFQzm z3O`P5$wa^Aaoky)+I}BTB@;`l%V|MGO8>9@c_fDI`rJzbGgHZo4Y7M?X=YzFPa+JP zPH&bjkwZ3x_0w|lCWcn8twM+FxQW6~nEiQodG1)JNOzSIUVr{XH~iff>sEPL+e{{& z1Ye1N?9W~|--PpJ`oDGrA$2iZY$)TQ1g&;D{}|HPq6?u@EjC#CtV$v44cEE4bR{K0 zKAy+D9X`%T`*lkGdG)XTIf*On0e7VdYA@Y}I6T7hgM{2%zGm0kW#!&wXDG(D&n5ZGl0wwMWnMO)7t9R&e_iF&UZoSnP8vJ;na+#82pJ8^5RYU;HIa zZl4fE*e8=1$-WM0a~o= z#N^Kk=N^T1J#1gt2Psvmt}jOx2NCLfSqHeUMu+R<5R`dW+^)vbrd#r5_>UW|RD?WLES#cGPF}hZRgpzsVgwK4e-gxTxr?W&)urni%FU4JNJsHg^Bd>+!?Ul$Q_kSPP*S2w#T!`YkfIx zTxfdS>+m%87kUhA@<$+A6y8Jr?qL#&?_a4OM(WX0KiaSU4IIJLbYIXp-|@vf_D^E7 zdAyV;yGDW{uNOmYhKSdvRIj7s*;MmXFS>B6rU%Oyw>~ec92T?KotzM&3@W7vUdVxO zoOZ^3a+=5T9zH>>mI*MY2`Xqsc*1{w6jruJvYF9E)MiEzN@-`G_)eB|xp2Xw&6K0} z3gXbJs#!lL@Xfd2?4!t3yc6gSO9=KOE_qh@uS3Ol=YB28I+wvQB*D+ar7W$VN0-j1 zUB}aQx2ngbaBiKa6s=O+W;Ae8bmsKq=7NU|(>iA2teX8an4A{;)GIyjvOmlQ5OeOpA1L`W2V&Ki4N8IK>dAbqTWJ%F=#|d{cbfz zTm0_VCPe%pg!XOzPguf1v1eCzxt+ldrvV7pu@9(UKr1CUK^PTygk}Tcs1*B%S5YQN z#;#%*mXkcnGbSjfG*GljFSXEA4w(J=5XpQzRqK1$QR>_p02Y$;MKNWbIU4f;^{LzPuWhMBQeM|X!>b)LPE zHGIlN7eDW_2X+4}3oynm8ufVbUN&ABJ=XPP5OFFTPLPoS*K2262C??LC~{p4tdpJ+ ztMsQ{%0;}Z+cq^h8XSqpWx`C71*OYJd5M10@N@(7dxD`M*0K-w(ukkzISV3g4!VzhQ2IuM#DGEGP>I^e|X`HKsOlP3jNw~M_!*)r)i0Aw=~N5 z88<`Mcj@g<0i`kM$EyqurF?eXT19##mrSMhE&kH`(Q)biEO#k2#)Y9iOq;80YRo-h zrjM#Vk~Q{cqgKH0OA|mNyu4n68S$tCJ}(l@Tno*2yzonEj{PQaxQ(WGeezS-%fJHm zQ2-Gyx|9apb-_#TzTBpcdQx3=0>kMBiP4ZchB{s`@M&KOWso|ve-?v(j6vCxaXKgG zPqIX1-c=+_4?)rB2aw5ROF2qD-Bq{#`lZZBSXT@1gP?qXhCcuP*PJ9>l0pI8acyE* zN8Q%h4;wKl~8Y+|gpM9PR$zqk^D%jYA7bADYvD%6eH$G5zjLev;xc#8GBtT*Eq zh*4t*-Van*8O^55Y;nl9aT?JdKAbNAJsT3wE39%;5dSKAJpD{##lF8>)esh4b)s;r zYoI*Hj$c;w#jSkFz(J>d_4Le>y0rWP7WYE(tt_6lOTY2|nKdAf$Tj*7eDD3X%(7kj zdvp@`Nz|%!3`>ccHGvEcgPykKiOt4 zg0n=0b|QK?(V!EM75|nCk8xZZHg0`|0`F-On4GQjNmT~EKj-yDfZw$dI~(TjM27nB zK3SHJq3KMTbHsk|YFli*ug&mgxVA;fdPMPKyMtI)1JPKl1IhI!?X<5a)0Yn#E0Lys zA6-MGAG(}+8b%2071a#LK>)*nOejJcT$)win} z0xr~1Tvg>GGa9p<##LZ9{T4K|e?LRAGz8wNi{NFp63UpG0xvd{c5r+&ezY8z=Pj;X zaZvH0l-K|_wGzl!d=3alnOEWKp;&WFTB4jfw_NH9R{E2KMY7IRe;ISe)GCcwwLWxOQda(ea1;GAY1!m#+G@|1J0; z&C_R(Vd9~S%jl{ADtth!>OEQjzRnbT+Q*`d9HWz_57t4zUZzAQHOWU0p_F_z2z3sp zb<4w4TMWho0DYyMH_&MgdM@Dep4h+qK-W5#ekBVE5_)4ysIvh_Esc-*+8!SL6Wq(| zLGdRFr7i?twHGS4^&lg}O^99k%T;x*A1kvMsyUiJwy$$2^?fH^O(&t6m>@sk4Jc?s zU+m!u9wLPBC#CiymZx9_z)=wh;)(y0E3Y zw#~(X!kzb-U66Xw6NJtu#co2{u8k-J05|B?M~psS0##ZZt*;xgLj1H>9BT)(!301Y zg~zoA0hxR73p>FYlFTijvz2b5C-EH&Nj%z~qqZKhlb#oRF$(UkH<-O0uR_HbE4s-( zhN-=3UB*E2ItaV0@5NM-;(ZsyrYX+n2I9CDpluiJ(Uas}?EpuGi2HWqT69V#i!yWf zp6d6Vn|D*VbxROP9w;IRw0Dd1OT8!ppa>v(X3*PcNmbe&RBj2DogPsO>9?U03@3e( zp)w+x(uCK&>nqaKY5+NcUhGJ5wFb!#v@&dnvO;h@i1xo(zJPRu`#xGoTKY;GNXr@; z$m%`G@M8AUPKw-Wh=#sGVBH9DrHshO_}9|+{}3%O3muGNq2l;kW=_w-$Hb-lHw48l z2veQGWFcgH3jZK4&tyEZZ@8pibG`qXkXBMvXYb(;Lr=nDl1ca!Fp1uf^U8hp2@d*} zps8;fm6!^HRNin&_{02Z=^3T9&0hi|tergk!@j=Zl~vU-4*VK#=i;7_p2f^3@#ANC zVrE`yc0R0RJ0&wWBq|}jxIVL>1Qm~*o|TW1N7m(wKRN+Ld`cROO(`y~WaJT7RM*8O zrc$$Te#^o|!Y!w7W=+bYAgQ2E%`F9sa`}aXlXA+y@EVwDkC;iAl2_g*EGj5E2}ZiW zs2#6>PzpW;@4zq*-#{8R0evf%kgqZBenD`}FI*z;gA+1S(lcl|gj~D=y@DcM^Q%V0 zCtEqVWL36W+Ss{#@#Rr8baeCKi-C7+n)f7;3{UBq#B76>lKRXCPYG(z zkkdD%I!|E$5VCU#C8q@U;6v0Vq#pvsq?4fRyyNz*T7P-5bn$BF=+&HmZn=12XgCU) zI_V!8nz_6+viEQci3J^AS8iP}XgKiyIwIEg%UL+qx3G(hi9-tMjfjd7bp8$$HDG8x zXL_feo|#FT`1>CKc2olq#3T#H-E!yx7bp_MYl)U+eNGst0N_!}`ck$f8-lMG)KHL+ zAOlB_=l!%8Vn!6NBx;F!Flas$M+xuzZtQ;l-cK$2ZUfD1SEst(Ayn^Al7Dn%{ z0v8r@G1~av51%-WWVuP$_L3j2#c`xftW`cuX24mNoetygmm4!` zkVuy}?`S1E|Mtg>x?ocz(R|za{#~<(|?3(21_nYm5hI@FV-zmLNcRROEp*D9fF^gQ4kb#!0K^O{3OEv z`35bec^azC#Cz6PHep^&ueE+c0`T#8#P=c zClDTu(V8+C*&lH;7(X_gG6cX;5*b3^*pMGVp}lAlj1hZp5=og;VirMWJD4BF;L!rp zRV2bF3HsE??I7ASkAi6NPGXB#?$mplXyDm9>NuX(NV7yW>Y*PAY!ugT>2KY^z#jDX{0{)OflJuue-kYz zqm`r;74_1+KtM6!H8p05a$w~o134`5 z!TPp2MU)J)^r4J;!z_KG+>A{yqGdeq1O~ve`Q-D#EPZS);51U0rSC5Qdzc^wbDzLv zD!~F*Gy391nr?qO?xM>QP2fZ+{N|1fpE$0*Lubf9X;MB1Y%I1LY)G*8+) zo|?2EtY3_41O815I|iw>G_rbVFPZaZF!O2Tp@-At)&c7`jjS2_=1C(w@NJcTJxW_%{NzE%{OLlFhIJDx{G`z(^o>4WZ^$yaX$?sTClC||_!k1-F9&ne$~Da2zC zDXCxyt08>k?m0^YE0oiQ`FaDpXk(#RP+eb{agYLSU z32pqgN5I)tp1BvhKf_iY_0fI4bh*);yCN}f0Ck#wy`{JaQa-_hYTxzIYFmd`DU~UR zzbfP`b_ypR-gZ+jY=35cs~qOb&`PZtibPT4=H9-eME9{(UWGH*Mrl`V?LLoF_N}*T z+cdVPfS|$nX@E?tX=ox&pV*70$KldC53w6`n7ztAW#6Fmm*MM?>lv?v+9R2Y$4WcpYRH1FU1Rx>5KEvxMn4F-spdGM zl$BUdV}gjP_%1^W@)^q$)Ws6Xw!EF0=}Qu?5PDghjSIxOlZ}1?YG-=&(x2; zesSDY59Lp9CmZbh4cYe#D=Oo>^msUl1wzLV$BTm3I18i} zpfiEkQS$V&D8!-e;z86WdA58+bmQPr?7{2z;%~_PQ4z@jHUqNX;61<1l4ywW{W^R* z=H1dGD(Fr5;kCN;(yCJ*Sz??r)Y}XpdyAg-$?$eqek{&rUv>RCd?H+YL&9!b@rab5 zwo7~`?jEGG-qzym7t##0iw7bd=t3nF3fy$xxnRH9RQv((-cKc)Nb?@x174j2@6)gW zAFu)W*hzrkTv)Nsf+1j#Al2keLJ$>y!G}qpe@C}0YY7Q?KGCcU1KuldQXuwu1pYWX zaCm^==o}Mp5dz1K4OfFreeXZ=J{Z;-@^+D-nGbgmE~IO~f~p3Pn`qRh!$9;7che+P z_8o&_OUNcDL>X|G7n|mm^aF|F8rFHHOMn!$zu<#U<;5O}-+I9i#^(zN3eA5PnGC@0io~Cd54TPK zM&I%+{;ecv7vtOBr^cV=wC-U7Dev^(e+gf}=m-p=8H{mWh~ekA9A4Buy^f@^A{BHu z;(cq}dFKLbbStxBWkm+=E@~ghSx0N>=KmdKgiUDi^49iO$|yor;npMWMoezzeP?~%6Df- zvm1=mFVRkxeQ=aVi~mLa34tDG{ea;RIfWlS8LDQ07m;F0m!#+AIkRPH`#Mc~KJ|P$ zYVe006wc-|nzqPfs^eGI3`)$Ao&e(@d!HdK|3jw16vj_*slNfKTZL&6zqIz{(iG5G z01v=TI*p9)ZkxLa80z|I0^e0q(!Wo8wQ!n*|6&2Y&#?NGAr=Ns`Vx-oj7i9*N8vNxTZL1NuE&| z&5|-SOXubTCzK~Ai^0^|(+G(7;nS8qKPLm}4>(WBq&f+>xgvCcjf5S&r~|Ue*35V0 z&z_p>pSDqQHW?TnL2vOTaAFxg_DtsO#8bk}<*Dc(Ljv)WO5hO~$v;V4 z=R@dB?45C@gQ##he^@x9=iK@MzfwkRpjom5P1N8&Tk2sR5Fid~m78c+Qe)x67dF>L zrS-_dfv{iOFu*~Uc z1=+1Kiq|F8Y?q6zkBXfcSxiZOx|K1x>iyGaj?TVP|I>e&Gk~OI{Zo+^W63ZzQg}v5 zxjKd?w5%ld8^hpLN#ZgC+iQ^|@6wDqgY?!?ckSXVNa+O?BRpK0mp5*VLRtEew?<%D z1xZ;Yq)Zf2mWR$;w_IkdRbF^h+9FuWg^R4!Se^wb2ceg#u~!rdV!?V_zGYMlLrUgn zDiV)4Cyy!y1uNr*E9NsQml=!HHp*9QOLT84M;NQVDwOX)ejf!A;@ zJF_jWqN%=OEJgxS-a#~4)kGd4)o_ZQ@%S}v%dZfRi)G-dZ@p^}^>8DHYi#v!bKzWpnm-`Uj_NV+jS*0HaMVUX4%%hz#3 zk283E>XW?c1f#N~OsYiM>YGU#e3lTT6dPQ;h%d2 z5%EfH{QOX1@YrZlF8n}UX*v>Vuh+yA)kI>`XsaKLSXAyX;%!9Oyo=i4cHCs>-F!OF zds^0P%-878)C}OL4=T5H(r!cs9k3eDNdwHPqjftp6+RvH3ewP3FIS z=1dMrq^+8kzY6tR^W0k#v~iJ2|Mr=SBQ)0twKeE7`f9Z`X4FJ~YYUyJer4X;zT(|2 z)ZRzR*g3*xq~9J>(!TZy7&_9fanmqKst*$CFxBdq&&-0GY+3Tr9$M)DLoqsgm^wEf zYjza11ARJ8!a9x~HF#$_b(Broj5YI;rEEpM8`fNI_GIAoV$f zRXY%A7|K~bi1{}!_NqD>1_-z+i~ZP6XfOGc*?mmgM)uTAN!FwBNnn-J^E+dY4OjQ8 z=pOWjZswB)xIiJcECr;EZZ0KBSD)UPmW{pz~IWK>jEs9(9E!LnU+I5hBhSE*l*NZTDBT3+0oI zG$_>y8;rDI)@Edlq}PwM3ky^{j`WPy)(emJKUJ1{kFxT#3=0c(u8u}(;FiOUjVO)f z()7(-Pqo^qw;a8Pmh!$yuG# z#Gf<8D1BX941HdZFeifbnJ1otK1VAc#xG@bEM+Kz#Qh|$Z7lA2mJ9u? zA$GH`2$mljm+wA-v`#7=`#0H^L}gC2EUJz;Z|XRDyU(%K#TfXXz8dVlcHQ}S#_rs)YoIb@bXIMWBUns6csZsno!6;Jv3GqrWq-z{_p+C*v1gyN zJ)|8GrMUCCldZgc-&mB@#-Aeyds_HxAKi5`9GY_wHPiYHe2`JU7wgZuT)Cg{!fIu7 zcr!hdZnT{VKFm4Oj(<5^#XI^@#gb-pbTYkL!pg?dc|^B;^t{zx_Rr}s&^E?U4BVOQ`3 z*q0rNbF>qGp8YRNFXtGYezN51=saDvLqGqC5b5~Ca@G3di2n~`cjwi^*;PAWMVyUk zHa_VhsC+eN_{8H#>pH0KIthS$~QQ_}j%jp9|T=fh_)kFp9jW!9NGHK>~7H zPsE@ts?c*&=zT79G!A;s_5cxkxDI%ls)j;Tfut(Xgfb|^>GC$<1tP|_HHn$Rs)I~} zoj#fS6%0M3#!e1A1Us>A1)}vEJOMPG&Z)7R%MVVIUv8+ettgQb{9i7pu^TqN#ri+( z!|ntsw~SsIi#{T&qCH`;v&oOMBwXnDAoCcJ$FO3jtC2%5v3)JZ)!f;)oRQgvevV_0 zDf%~BP3FSEC`dJOu<+9rY@!J}o6Wc)1^aaA!LlmUwg?J|d$SFd+lM~DZim&-sxIEM z>Zj}Kvgh2pXXu}MNHz407!;5T{ri~hzBmaA$%YO@`1h@g73CQL1NP7af4rNr=6HT_@w?Q?l{X0qnhqdqGl$>i&Sb!d*ac zF6wa}&7Gg70$%crpZvX9df$|6^^BJc-{jg7qWP7+?Z*BYT!u=H*e5|Y?ajjK%EDaR zAS?8!>v{%Cc;y__zyHF#u*LcJ7EHKr1gwuc{(HX%PtmTSK9^@7o9rt*v32_nv&$JF zRVC~I?C)P3wErId=U@NV84w2$$z=j5QFuQG-xBK1^3mm=F&vLA{{NrZ(-{?ihf!Bf z+cx~Y?rFjQcSXf=8k(Er*i*XlAol`Q| zrRYgAgkfiDfB+++`4n_TbM)fC;7rPmzP<^QPBf0ui2|yP0@wjul%d#P&CVB;I%fTe-xne51Pu/dev/null ``` **Step 2** — pack the wizard: ```bash -cd cli +cd "$OPEN_DAIMON_REPO/cli" npm pack --pack-destination /tmp/ ``` @@ -57,6 +63,10 @@ cd /tmp/test-pack npx file:/tmp/ngirchev-open-daimon-1.0.1.tgz --local-image ``` +If you choose `Start the stack now?`, the wizard checks that `open-daimon:local` exists before `docker compose up -d`. +If the image is missing, it stops with the build command instead of partially creating containers and failing with +`No such image: open-daimon:local`. + --- ## Setup (once) diff --git a/cli/bin/setup.js b/cli/bin/setup.js index d300926f..09d067da 100644 --- a/cli/bin/setup.js +++ b/cli/bin/setup.js @@ -1,6 +1,6 @@ #!/usr/bin/env node import { input, password, select, checkbox, confirm } from '@inquirer/prompts'; -import { execSync, spawn } from 'child_process'; +import { execFileSync, execSync, spawn } from 'child_process'; import { existsSync, readFileSync, writeFileSync, rmSync, statSync } from 'fs'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; @@ -24,6 +24,15 @@ function checkCommand(cmd) { } } +function dockerImageExists(image) { + try { + execFileSync('docker', ['image', 'inspect', image], { stdio: 'ignore' }); + return true; + } catch { + return false; + } +} + async function checkOllama(url) { try { const res = await fetch(url, { signal: AbortSignal.timeout(3000) }); @@ -49,9 +58,17 @@ function spawnAsync(cmd, args, cwd) { return new Promise((resolve) => { const proc = spawn(cmd, args, { stdio: 'inherit', cwd }); proc.on('close', resolve); + proc.on('error', () => resolve(1)); }); } +async function runCommand(cmd, args, cwd) { + const code = await spawnAsync(cmd, args, cwd); + if (code !== 0) { + throw new Error(`Command failed: ${[cmd, ...args].join(' ')}`); + } +} + async function waitForApp(url, timeoutMs = 120000) { const start = Date.now(); process.stdout.write('\nWaiting for app to be ready'); @@ -393,14 +410,28 @@ async function main() { default: true, }); if (doStart) { - console.log('\nDownloading images (this may take a few minutes on first run)...'); - await spawnAsync(composeCmd[0], [...composeCmd.slice(1), 'pull'], TARGET_DIR); + if (USE_LOCAL_IMAGE) { + if (!dockerImageExists(APP_IMAGE)) { + console.error(`\nLocal Docker image ${APP_IMAGE} was not found.`); + console.error('Build it from the open-daimon repository root first.'); + console.error('If you are in the repository cli/ directory, run:'); + console.error(' OPEN_DAIMON_REPO="$(cd .. && pwd)"'); + console.error(` docker build -t ${APP_IMAGE} "$OPEN_DAIMON_REPO"`); + console.error('\nThen start the generated stack from this directory:'); + console.error(' docker compose up -d'); + process.exit(1); + } + console.log(`\nUsing local Docker image ${APP_IMAGE}.`); + } else { + console.log('\nDownloading images (this may take a few minutes on first run)...'); + await runCommand(composeCmd[0], [...composeCmd.slice(1), 'pull'], TARGET_DIR); + } console.log('\nStarting containers...'); - await spawnAsync(composeCmd[0], [...composeCmd.slice(1), 'up', '-d'], TARGET_DIR); + await runCommand(composeCmd[0], [...composeCmd.slice(1), 'up', '-d'], TARGET_DIR); console.log('\nContainer status:'); - await spawnAsync(composeCmd[0], [...composeCmd.slice(1), 'ps'], TARGET_DIR); + await runCommand(composeCmd[0], [...composeCmd.slice(1), 'ps'], TARGET_DIR); await waitForApp('http://localhost:8080/actuator/health'); } diff --git a/docs/codex/setup.md b/docs/codex/setup.md index 47abf5c1..a878d0e4 100644 --- a/docs/codex/setup.md +++ b/docs/codex/setup.md @@ -93,6 +93,18 @@ memories = true Hooks should remain optional for building and testing OpenDaimon. A fresh agent must still be able to work from `AGENTS.md`, the Maven project, and the MCP templates. +## Codex Subagents + +Project-level subagent behavior is documented in `AGENTS.md`, not in a committed personal `~/.codex/config.toml`. + +For this repository, small explicitly delegated side tasks should use the Spark-backed Codex model: + +```text +model: gpt-5.3-codex-spark +``` + +Use it for narrow lookup, verification, or small disjoint patches. Keep larger design work, risky edits, and immediate blockers on the main model unless the user asks for broader delegation. + ## Smoke Check From the repository root, start a new Codex session and check: diff --git a/docs/setup-telegram.md b/docs/setup-telegram.md index 3789c505..e29cc2a0 100644 --- a/docs/setup-telegram.md +++ b/docs/setup-telegram.md @@ -27,7 +27,7 @@ Your admin ID is your numeric Telegram user ID. To find it: First: John ... ``` - The `Id` value is your **`ADMIN_TELEGRAM_ID`**. + Put the `Id` value into **`TELEGRAM_ACCESS_ADMIN_IDS`**. ## Step 3: (Optional) Allow bot in groups @@ -56,5 +56,5 @@ If your token is compromised: ## Notes - The bot will only respond to users listed in `TELEGRAM_ACCESS_*_IDS` or channels in `TELEGRAM_ACCESS_*_CHANNELS` -- As admin, you are added automatically (via `ADMIN_TELEGRAM_ID`) +- Add your own user ID to `TELEGRAM_ACCESS_ADMIN_IDS` to get admin access - See [User Priorities](../README.md#user-priorities-and-bulkhead) for how access levels work diff --git a/docs/team/archunit-rules.md b/docs/team/archunit-rules.md index 95d63684..8fe08703 100644 --- a/docs/team/archunit-rules.md +++ b/docs/team/archunit-rules.md @@ -3,7 +3,7 @@ slug: archunit-rules title: "ArchUnit Architecture Rules" owner: ngirchev created: 2026-04-28 -updated: 2026-05-01 +updated: 2026-05-03 status: done base_branch: fsm --- @@ -34,6 +34,8 @@ Out of scope: - `opendaimon-gateway-mock` - application runtime wiring beyond the existing cross-module `ArchitectureTest` +`opendaimon-ui` and `opendaimon-gateway-mock` are intentionally out of scope for module-local ArchUnit suites. They are thin support modules without independent repository/domain/service layering. For those modules, use compile checks, dependency analysis/enforcer checks, and focused behavior tests when behavior changes. Reconsider ArchUnit only if either module grows stable internal architectural boundaries that need executable enforcement. + ## Rule Set ### Cross-Module Rules diff --git a/docs/usecases/doc-xls-tika-rag.md b/docs/usecases/doc-xls-tika-rag.md index 1707077a..7bb55566 100644 --- a/docs/usecases/doc-xls-tika-rag.md +++ b/docs/usecases/doc-xls-tika-rag.md @@ -4,7 +4,9 @@ > - `DocRagOllamaManualIT`, `DocRagOpenRouterManualIT` — DOC files > - `XlsRagOllamaManualIT`, `XlsRagOpenRouterManualIT` — XLS files > -> Run with: `./mvnw -pl opendaimon-app -am clean test-compile failsafe:integration-test failsafe:verify -Dit.test= -Dfailsafe.failIfNoSpecifiedTests=false -Dmanual.ollama.e2e=true` +> Run with `-Dmanual.ollama.e2e=true` for `*OllamaManualIT` classes or +> `-Dmanual.openrouter.e2e=true` for `*OpenRouterManualIT` classes: +> `./mvnw -pl opendaimon-app -am clean test-compile failsafe:integration-test failsafe:verify -Dit.test= -Dfailsafe.failIfNoSpecifiedTests=false ...` When a user uploads a DOC, XLS, DOCX, XLSX or other office document, the system extracts text via Apache Tika (through Spring AI's `TikaDocumentReader`), indexes chunks in diff --git a/docs/usecases/image-pdf-vision-cache.md b/docs/usecases/image-pdf-vision-cache.md index 4fa14027..63f34fac 100644 --- a/docs/usecases/image-pdf-vision-cache.md +++ b/docs/usecases/image-pdf-vision-cache.md @@ -3,9 +3,11 @@ > **Fixture test:** `ImagePdfVisionCacheFixtureIT` — run with `./mvnw clean verify -pl opendaimon-app -am -Pfixture` > > **Manual tests:** -> - `ImagePdfVisionRagOllamaManualIT` — `image-based-pdf-sample.pdf` with OCR via gemma3:4b +> - `ImagePdfVisionRagOllamaManualIT`, `ImagePdfVisionRagOpenRouterManualIT` — `image-based-pdf-sample.pdf` with OCR via a vision model > -> Run with: `./mvnw -pl opendaimon-app -am clean test-compile failsafe:integration-test failsafe:verify -Dit.test=ImagePdfVisionRagOllamaManualIT -Dfailsafe.failIfNoSpecifiedTests=false -Dmanual.ollama.e2e=true` +> Run with `-Dmanual.ollama.e2e=true` for `ImagePdfVisionRagOllamaManualIT` or +> `-Dmanual.openrouter.e2e=true` for `ImagePdfVisionRagOpenRouterManualIT`: +> `./mvnw -pl opendaimon-app -am clean test-compile failsafe:integration-test failsafe:verify -Dit.test= -Dfailsafe.failIfNoSpecifiedTests=false ...` When a user uploads an image-only PDF (scan, certificate, etc.), the system detects it before the gateway call, renders pages as images, extracts text via a vision-capable model, diff --git a/docs/usecases/image-vision-direct.md b/docs/usecases/image-vision-direct.md index bca42237..aee3190f 100644 --- a/docs/usecases/image-vision-direct.md +++ b/docs/usecases/image-vision-direct.md @@ -4,7 +4,9 @@ > - `ObjectsImageVisionOllamaManualIT`, `ObjectsImageVisionOpenRouterManualIT` — photo of objects > - `GreekImageVisionOllamaManualIT`, `GreekImageVisionOpenRouterManualIT` — image with Greek text > -> Run with: `./mvnw -pl opendaimon-app -am clean test-compile failsafe:integration-test failsafe:verify -Dit.test= -Dfailsafe.failIfNoSpecifiedTests=false -Dmanual.ollama.e2e=true` +> Run with `-Dmanual.ollama.e2e=true` for `*OllamaManualIT` classes or +> `-Dmanual.openrouter.e2e=true` for `*OpenRouterManualIT` classes: +> `./mvnw -pl opendaimon-app -am clean test-compile failsafe:integration-test failsafe:verify -Dit.test= -Dfailsafe.failIfNoSpecifiedTests=false ...` When a user uploads a JPEG/PNG image (not a PDF), the system sends it directly to a vision-capable model as a `Media` object. **No RAG indexing is performed** — images bypass diff --git a/docs/usecases/text-pdf-rag.md b/docs/usecases/text-pdf-rag.md index f9e7c0fa..c72d1497 100644 --- a/docs/usecases/text-pdf-rag.md +++ b/docs/usecases/text-pdf-rag.md @@ -6,7 +6,9 @@ > - `TextPdfRagOllamaManualIT`, `TextPdfRagOpenRouterManualIT` — single-page `sample.pdf` with follow-up RAG > - `ImagesWithTextPdfVisionRagOllamaManualIT`, `ImagesWithTextPdfVisionRagOpenRouterManualIT` — 3-page `images_with_text.pdf` with cross-chunk RAG retrieval > -> Run with: `./mvnw -pl opendaimon-app -am clean test-compile failsafe:integration-test failsafe:verify -Dit.test= -Dfailsafe.failIfNoSpecifiedTests=false -Dmanual.ollama.e2e=true` +> Run with `-Dmanual.ollama.e2e=true` for `*OllamaManualIT` classes or +> `-Dmanual.openrouter.e2e=true` for `*OpenRouterManualIT` classes: +> `./mvnw -pl opendaimon-app -am clean test-compile failsafe:integration-test failsafe:verify -Dit.test= -Dfailsafe.failIfNoSpecifiedTests=false ...` When a user uploads a PDF with a text layer (selectable text), the system extracts text via PDFBox, indexes chunks in VectorStore, and builds an augmented prompt for the LLM. diff --git a/opendaimon-app/pom.xml b/opendaimon-app/pom.xml index 46150ee4..a8aa63eb 100644 --- a/opendaimon-app/pom.xml +++ b/opendaimon-app/pom.xml @@ -222,6 +222,11 @@ junit-jupiter-api test + + org.junit.jupiter + junit-jupiter-engine + test + org.mockito mockito-core @@ -298,6 +303,9 @@ net.logstash.logback:logstash-logback-encoder org.apache.pdfbox:pdfbox-io org.springframework.boot:spring-boot-testcontainers + + org.junit.jupiter:junit-jupiter-engine org.testcontainers:junit-jupiter com.h2database:h2 com.tngtech.archunit:archunit-junit5 diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/AgentModeOllamaManualIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/AgentModeOllamaManualIT.java index 00e14335..bbfef8ec 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/AgentModeOllamaManualIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/AgentModeOllamaManualIT.java @@ -12,6 +12,8 @@ import io.github.ngirchev.opendaimon.common.model.OpenDaimonMessage; import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; import io.github.ngirchev.opendaimon.common.repository.OpenDaimonMessageRepository; +import io.github.ngirchev.opendaimon.it.manual.support.ManualScenarioCache; +import io.github.ngirchev.opendaimon.it.manual.support.ManualTestPrerequisites; import io.github.ngirchev.opendaimon.telegram.TelegramBot; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; @@ -28,12 +30,12 @@ import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import org.springframework.beans.factory.annotation.Autowired; @@ -52,10 +54,6 @@ import org.telegram.telegrambots.meta.exceptions.TelegramApiException; import java.io.IOException; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; import lombok.extern.slf4j.Slf4j; import java.time.Duration; @@ -71,7 +69,6 @@ import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; @@ -104,6 +101,7 @@ @EnabledIfSystemProperty(named = "manual.ollama.e2e", matches = "true") @SpringBootTest(classes = AgentModeOllamaManualIT.TestConfig.class) @ActiveProfiles({"integration-test", "manual-ollama"}) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) @Slf4j class AgentModeOllamaManualIT extends AbstractContainerIT { @@ -136,6 +134,11 @@ class AgentModeOllamaManualIT extends AbstractContainerIT { private static final MockWebServer mockWebServer = createMockWebServer(); + private final ManualScenarioCache adminReactWebSearchScenario = + ManualScenarioCache.of(this::runAdminReactWebSearchScenario); + private final ManualScenarioCache regularSimpleScenario = + ManualScenarioCache.of(this::runRegularSimpleScenario); + @Autowired private MessageTelegramCommandHandler messageHandler; @@ -165,7 +168,7 @@ class AgentModeOllamaManualIT extends AbstractContainerIT { @BeforeAll static void checkOllama() { - requireLocalOllamaWithModels(); + ManualTestPrerequisites.requireLocalOllamaWithModels(REQUIRED_OLLAMA_MODELS, OLLAMA_TIMEOUT); } @AfterAll @@ -200,21 +203,7 @@ void setUpEach() throws TelegramApiException { @Test @Timeout(3 * 60) @DisplayName("ADMIN: agent uses REACT strategy and invokes web_search tool") - void admin_agentReact_invokesWebSearch() { - TelegramCommand command = createMessageCommand( - ADMIN_CHAT_ID, - 1, - "Какая последняя версия Spring Boot вышла в 2026 году? Поищи в интернете." - ); - - messageHandler.handle(command); - - TelegramUser user = telegramUserRepository.findByTelegramId(ADMIN_CHAT_ID) - .orElseThrow(() -> new IllegalStateException("Telegram user should be created")); - - ConversationThread thread = threadRepository.findMostRecentActiveThread(user) - .orElseThrow(() -> new IllegalStateException("Active thread should exist")); - + void admin_agentReact_invokesWebSearch() throws Exception { // The primary goal of this test is to verify that ADMIN users activate // REACT strategy (not SIMPLE). With a 3B model, the LLM may occasionally: // - invoke tools and produce a response (ideal path) @@ -222,10 +211,9 @@ void admin_agentReact_invokesWebSearch() { // - return an empty response causing agent FAILED state (known 3B quirk) // All three outcomes confirm that REACT was activated and the pipeline // ran end-to-end. We verify at least one assistant message was persisted. - List assistantMessages = messageRepository - .findByThreadAndRoleOrderBySequenceNumberAsc(thread, MessageRole.ASSISTANT); + HandledCommandResult result = adminReactWebSearchScenario.get(); - assertThat(assistantMessages) + assertThat(result.assistantMessages()) .as("Handler must save an assistant message (even on agent FAILED state)") .isNotEmpty(); } @@ -235,32 +223,18 @@ void admin_agentReact_invokesWebSearch() { @Test @Timeout(3 * 60) @DisplayName("REGULAR: agent uses SIMPLE strategy without tools") - void regular_agentSimple_noTools() { - TelegramCommand command = createMessageCommand( - REGULAR_CHAT_ID, - 2, - "Привет, расскажи анекдот" - ); - - messageHandler.handle(command); - - TelegramUser user = telegramUserRepository.findByTelegramId(REGULAR_CHAT_ID) - .orElseThrow(() -> new IllegalStateException("Telegram user should be created")); - - ConversationThread thread = threadRepository.findMostRecentActiveThread(user) - .orElseThrow(() -> new IllegalStateException("Active thread should exist")); - - String assistantReply = latestAssistantReply(thread); + void regular_agentSimple_noTools() throws Exception { + HandledCommandResult result = regularSimpleScenario.get(); - assertThat(assistantReply) + assertThat(result.assistantReply()) .as("SIMPLE agent should produce a non-blank response") .isNotBlank(); - assertThat(WEB_SEARCH_CALLED.get()) + assertThat(result.webSearchCalled()) .as("REGULAR (CHAT-only) should NOT invoke web_search") .isFalse(); - assertThat(FETCH_URL_CALLED.get()) + assertThat(result.fetchUrlCalled()) .as("REGULAR (CHAT-only) should NOT invoke fetch_url") .isFalse(); } @@ -270,35 +244,18 @@ void regular_agentSimple_noTools() { @Test @Timeout(3 * 60) @DisplayName("Agent response saved to DB with correct structure") - void agentResponse_persistedToDb() { - TelegramCommand command = createMessageCommand( - ADMIN_CHAT_ID, - 3, - "Скажи одним словом: работает ли агент?" - ); - - messageHandler.handle(command); - - TelegramUser user = telegramUserRepository.findByTelegramId(ADMIN_CHAT_ID) - .orElseThrow(); + void agentResponse_persistedToDb() throws Exception { + HandledCommandResult result = regularSimpleScenario.get(); - ConversationThread thread = threadRepository.findMostRecentActiveThread(user) - .orElseThrow(); - - List userMessages = messageRepository - .findByThreadAndRoleOrderBySequenceNumberAsc(thread, MessageRole.USER); - List assistantMessages = messageRepository - .findByThreadAndRoleOrderBySequenceNumberAsc(thread, MessageRole.ASSISTANT); - - assertThat(userMessages) + assertThat(result.userMessages()) .as("User message should be saved") .hasSize(1); - assertThat(assistantMessages) + assertThat(result.assistantMessages()) .as("Assistant message should be saved") .hasSize(1); - assertThat(assistantMessages.getFirst().getContent()) + assertThat(result.assistantMessages().getFirst().getContent()) .as("Assistant content should not be blank") .isNotBlank(); } @@ -706,6 +663,47 @@ void admin_reactStrategy_thinkingAndToolCallSentToTelegram() throws TelegramApiE // --- Helpers --- + private HandledCommandResult runAdminReactWebSearchScenario() { + TelegramCommand command = createMessageCommand( + ADMIN_CHAT_ID, + 1, + "Какая последняя версия Spring Boot вышла в 2026 году? Поищи в интернете." + ); + return handleCommand(command, ADMIN_CHAT_ID); + } + + private HandledCommandResult runRegularSimpleScenario() { + TelegramCommand command = createMessageCommand( + REGULAR_CHAT_ID, + 2, + "Привет, расскажи анекдот" + ); + return handleCommand(command, REGULAR_CHAT_ID); + } + + private HandledCommandResult handleCommand(TelegramCommand command, Long chatId) { + messageHandler.handle(command); + + TelegramUser user = telegramUserRepository.findByTelegramId(chatId) + .orElseThrow(() -> new IllegalStateException("Telegram user should be created")); + ConversationThread thread = threadRepository.findMostRecentActiveThread(user) + .orElseThrow(() -> new IllegalStateException("Active thread should exist")); + List userMessages = messageRepository + .findByThreadAndRoleOrderBySequenceNumberAsc(thread, MessageRole.USER); + List assistantMessages = messageRepository + .findByThreadAndRoleOrderBySequenceNumberAsc(thread, MessageRole.ASSISTANT); + String assistantReply = assistantMessages.isEmpty() ? "" : assistantMessages.getLast().getContent(); + return new HandledCommandResult( + userMessages, + assistantMessages, + assistantReply, + WEB_SEARCH_CALLED.get(), + FETCH_URL_CALLED.get(), + HTTP_GET_CALLED.get(), + TOOL_CALL_COUNT.get() + ); + } + private TelegramCommand createMessageCommand(Long chatId, int messageId, String text) { Update update = new Update(); @@ -783,37 +781,15 @@ private static MockWebServer createMockWebServer() { return server; } - static void requireLocalOllamaWithModels() { - String baseUrl = resolveOllamaBaseUrl(); - HttpClient client = HttpClient.newBuilder() - .connectTimeout(OLLAMA_TIMEOUT) - .build(); - HttpRequest request = HttpRequest.newBuilder() - .GET() - .timeout(OLLAMA_TIMEOUT) - .uri(URI.create(baseUrl + "/api/tags")) - .build(); - try { - HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); - boolean statusOk = response.statusCode() == 200; - boolean modelsPresent = REQUIRED_OLLAMA_MODELS.stream().allMatch(response.body()::contains); - Assumptions.assumeTrue(statusOk && modelsPresent, - "Skipping: Ollama/models unavailable at " + baseUrl + ". Required: " + REQUIRED_OLLAMA_MODELS); - } catch (Exception ex) { - Assumptions.assumeTrue(false, - "Skipping: cannot connect to Ollama at " + baseUrl + ". " + ex.getMessage()); - } - } - - private static String resolveOllamaBaseUrl() { - String baseUrl = System.getenv("OLLAMA_BASE_URL"); - if (baseUrl == null || baseUrl.isBlank()) { - baseUrl = "http://localhost:11434"; - } - if (baseUrl.endsWith("/")) { - return baseUrl.substring(0, baseUrl.length() - 1); - } - return baseUrl; + private record HandledCommandResult( + List userMessages, + List assistantMessages, + String assistantReply, + boolean webSearchCalled, + boolean fetchUrlCalled, + boolean httpGetCalled, + int toolCallCount + ) { } @SpringBootConfiguration diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/AgentModeOpenRouterManualIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/AgentModeOpenRouterManualIT.java index 295871bd..648b42fb 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/AgentModeOpenRouterManualIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/AgentModeOpenRouterManualIT.java @@ -1,6 +1,5 @@ package io.github.ngirchev.opendaimon.it.manual; -import io.github.ngirchev.dotenv.DotEnvLoader; import io.github.ngirchev.opendaimon.ai.springai.tool.HttpApiTool; import io.github.ngirchev.opendaimon.ai.springai.tool.WebTools; import io.github.ngirchev.opendaimon.common.agent.AgentExecutor; @@ -9,6 +8,8 @@ import io.github.ngirchev.opendaimon.common.model.OpenDaimonMessage; import io.github.ngirchev.opendaimon.common.repository.ConversationThreadRepository; import io.github.ngirchev.opendaimon.common.repository.OpenDaimonMessageRepository; +import io.github.ngirchev.opendaimon.it.manual.support.ManualScenarioCache; +import io.github.ngirchev.opendaimon.it.manual.support.ManualTestPrerequisites; import io.github.ngirchev.opendaimon.telegram.TelegramBot; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; @@ -25,12 +26,12 @@ import okhttp3.mockwebserver.MockWebServer; import okhttp3.mockwebserver.RecordedRequest; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.Assumptions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.Timeout; import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import org.springframework.beans.factory.annotation.Autowired; @@ -49,7 +50,6 @@ import org.telegram.telegrambots.meta.exceptions.TelegramApiException; import java.io.IOException; -import java.nio.file.Path; import java.time.Duration; import java.util.List; import java.util.Set; @@ -107,12 +107,9 @@ } ) @ActiveProfiles({"integration-test", "manual-openrouter"}) +@TestInstance(TestInstance.Lifecycle.PER_CLASS) class AgentModeOpenRouterManualIT extends AbstractContainerIT { - static { - DotEnvLoader.loadDotEnv(Path.of("../.env")); - } - private static final Long ADMIN_CHAT_ID = 350009010L; private static final Long REGULAR_CHAT_ID = 350009012L; @@ -135,6 +132,11 @@ class AgentModeOpenRouterManualIT extends AbstractContainerIT { private static final MockWebServer mockWebServer = createMockWebServer(); + private final ManualScenarioCache adminReactWebSearchScenario = + ManualScenarioCache.of(this::runAdminReactWebSearchScenario); + private final ManualScenarioCache regularSimpleScenario = + ManualScenarioCache.of(this::runRegularSimpleScenario); + @Autowired private MessageTelegramCommandHandler messageHandler; @@ -164,12 +166,7 @@ class AgentModeOpenRouterManualIT extends AbstractContainerIT { @BeforeAll static void requireOpenRouterKey() { - DotEnvLoader.loadDotEnv(Path.of("../.env")); - String openRouterKey = System.getProperty("OPENROUTER_KEY", System.getenv("OPENROUTER_KEY")); - Assumptions.assumeTrue( - openRouterKey != null && !openRouterKey.isBlank() && !openRouterKey.equals("sk-placeholder"), - "Skipping manual test: OPENROUTER_KEY not set in .env or environment" - ); + ManualTestPrerequisites.requireOpenRouterKey(); } @AfterAll @@ -200,30 +197,13 @@ void setUpEach() throws TelegramApiException { @Test @Timeout(3 * 60) @DisplayName("B1: ADMIN agent uses REACT strategy and invokes web_search via OpenRouter") - void admin_agentReact_invokesWebSearch() { - TelegramCommand command = createMessageCommand( - ADMIN_CHAT_ID, - 1, - "What is the latest version of Spring Boot released in 2026? Search the internet." - ); - - messageHandler.handle(command); - - TelegramUser user = telegramUserRepository.findByTelegramId(ADMIN_CHAT_ID) - .orElseThrow(() -> new IllegalStateException("Telegram user should be created")); - - ConversationThread thread = threadRepository.findMostRecentActiveThread(user) - .orElseThrow(() -> new IllegalStateException("Active thread should exist")); - - String assistantReply = latestAssistantReply(thread); - + void admin_agentReact_invokesWebSearch() throws Exception { // The primary goal is to verify that ADMIN activates REACT strategy. // LLM may occasionally return an empty response (known quirk in batch runs). // All outcomes confirm the pipeline ran end-to-end. - List assistantMessages = messageRepository - .findByThreadAndRoleOrderBySequenceNumberAsc(thread, MessageRole.ASSISTANT); + HandledCommandResult result = adminReactWebSearchScenario.get(); - assertThat(assistantMessages) + assertThat(result.assistantMessages()) .as("Handler must save an assistant message (even on agent FAILED state)") .isNotEmpty(); } @@ -273,35 +253,18 @@ void admin_agentReact_chainsWebSearchAndFetchUrl() { @Test @Timeout(3 * 60) @DisplayName("B3: Agent response saved to DB with correct structure (OpenRouter)") - void agentResponse_persistedToDb() { - TelegramCommand command = createMessageCommand( - ADMIN_CHAT_ID, - 3, - "Answer in one word: is the agent working?" - ); + void agentResponse_persistedToDb() throws Exception { + HandledCommandResult result = regularSimpleScenario.get(); - messageHandler.handle(command); - - TelegramUser user = telegramUserRepository.findByTelegramId(ADMIN_CHAT_ID) - .orElseThrow(); - - ConversationThread thread = threadRepository.findMostRecentActiveThread(user) - .orElseThrow(); - - List userMessages = messageRepository - .findByThreadAndRoleOrderBySequenceNumberAsc(thread, MessageRole.USER); - List assistantMessages = messageRepository - .findByThreadAndRoleOrderBySequenceNumberAsc(thread, MessageRole.ASSISTANT); - - assertThat(userMessages) + assertThat(result.userMessages()) .as("User message should be saved") .hasSize(1); - assertThat(assistantMessages) + assertThat(result.assistantMessages()) .as("Assistant message should be saved") .hasSize(1); - assertThat(assistantMessages.getFirst().getContent()) + assertThat(result.assistantMessages().getFirst().getContent()) .as("Assistant content should not be blank") .isNotBlank(); } @@ -430,32 +393,18 @@ void admin_agentReact_invokesHttpGet() { @Test @Timeout(3 * 60) @DisplayName("B4: REGULAR agent uses SIMPLE strategy without tools (OpenRouter)") - void regular_agentSimple_noTools() { - TelegramCommand command = createMessageCommand( - REGULAR_CHAT_ID, - 4, - "Tell me a short joke" - ); + void regular_agentSimple_noTools() throws Exception { + HandledCommandResult result = regularSimpleScenario.get(); - messageHandler.handle(command); - - TelegramUser user = telegramUserRepository.findByTelegramId(REGULAR_CHAT_ID) - .orElseThrow(() -> new IllegalStateException("Telegram user should be created")); - - ConversationThread thread = threadRepository.findMostRecentActiveThread(user) - .orElseThrow(() -> new IllegalStateException("Active thread should exist")); - - String assistantReply = latestAssistantReply(thread); - - assertThat(assistantReply) + assertThat(result.assistantReply()) .as("SIMPLE agent should produce a non-blank response") .isNotBlank(); - assertThat(WEB_SEARCH_CALLED.get()) + assertThat(result.webSearchCalled()) .as("REGULAR (CHAT-only) should NOT invoke web_search") .isFalse(); - assertThat(FETCH_URL_CALLED.get()) + assertThat(result.fetchUrlCalled()) .as("REGULAR (CHAT-only) should NOT invoke fetch_url") .isFalse(); } @@ -550,6 +499,47 @@ private io.github.ngirchev.opendaimon.common.model.Attachment loadImageAttachmen // --- Helpers --- + private HandledCommandResult runAdminReactWebSearchScenario() { + TelegramCommand command = createMessageCommand( + ADMIN_CHAT_ID, + 1, + "What is the latest version of Spring Boot released in 2026? Search the internet." + ); + return handleCommand(command, ADMIN_CHAT_ID); + } + + private HandledCommandResult runRegularSimpleScenario() { + TelegramCommand command = createMessageCommand( + REGULAR_CHAT_ID, + 4, + "Tell me a short joke" + ); + return handleCommand(command, REGULAR_CHAT_ID); + } + + private HandledCommandResult handleCommand(TelegramCommand command, Long chatId) { + messageHandler.handle(command); + + TelegramUser user = telegramUserRepository.findByTelegramId(chatId) + .orElseThrow(() -> new IllegalStateException("Telegram user should be created")); + ConversationThread thread = threadRepository.findMostRecentActiveThread(user) + .orElseThrow(() -> new IllegalStateException("Active thread should exist")); + List userMessages = messageRepository + .findByThreadAndRoleOrderBySequenceNumberAsc(thread, MessageRole.USER); + List assistantMessages = messageRepository + .findByThreadAndRoleOrderBySequenceNumberAsc(thread, MessageRole.ASSISTANT); + String assistantReply = assistantMessages.isEmpty() ? "" : assistantMessages.getLast().getContent(); + return new HandledCommandResult( + userMessages, + assistantMessages, + assistantReply, + WEB_SEARCH_CALLED.get(), + FETCH_URL_CALLED.get(), + HTTP_GET_CALLED.get(), + TOOL_CALL_COUNT.get() + ); + } + private TelegramCommand createMessageCommand(Long chatId, int messageId, String text) { return createMessageCommand(chatId, messageId, text, "en"); } @@ -632,6 +622,17 @@ public MockResponse dispatch(RecordedRequest request) { return server; } + private record HandledCommandResult( + List userMessages, + List assistantMessages, + String assistantReply, + boolean webSearchCalled, + boolean fetchUrlCalled, + boolean httpGetCalled, + int toolCallCount + ) { + } + @SpringBootConfiguration @EnableAutoConfiguration static class TestConfig { diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/DocRagOpenRouterManualIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/DocRagOpenRouterManualIT.java index 4fa4c1b0..b82d1c8a 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/DocRagOpenRouterManualIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/DocRagOpenRouterManualIT.java @@ -83,7 +83,7 @@ * */ @Tag("manual") -@EnabledIfSystemProperty(named = "manual.ollama.e2e", matches = "true") +@EnabledIfSystemProperty(named = "manual.openrouter.e2e", matches = "true") @SpringBootTest( classes = OpenRouterSimpleManualTestConfig.class, properties = "open-daimon.agent.enabled=false" diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/GreekImageVisionOpenRouterManualIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/GreekImageVisionOpenRouterManualIT.java index 3ef58213..efc9a1c0 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/GreekImageVisionOpenRouterManualIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/GreekImageVisionOpenRouterManualIT.java @@ -79,7 +79,7 @@ * */ @Tag("manual") -@EnabledIfSystemProperty(named = "manual.ollama.e2e", matches = "true") +@EnabledIfSystemProperty(named = "manual.openrouter.e2e", matches = "true") @SpringBootTest( classes = OpenRouterSimpleManualTestConfig.class, properties = "open-daimon.agent.enabled=false" diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/ImagePdfVisionRagOpenRouterManualIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/ImagePdfVisionRagOpenRouterManualIT.java index 90bd9ae2..665ebe49 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/ImagePdfVisionRagOpenRouterManualIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/ImagePdfVisionRagOpenRouterManualIT.java @@ -87,7 +87,7 @@ * */ @Tag("manual") -@EnabledIfSystemProperty(named = "manual.ollama.e2e", matches = "true") +@EnabledIfSystemProperty(named = "manual.openrouter.e2e", matches = "true") @SpringBootTest( classes = OpenRouterSimpleManualTestConfig.class, properties = "open-daimon.agent.enabled=false" diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/ImagesWithTextPdfVisionRagOpenRouterManualIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/ImagesWithTextPdfVisionRagOpenRouterManualIT.java index 988cc6c3..b634cbc8 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/ImagesWithTextPdfVisionRagOpenRouterManualIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/ImagesWithTextPdfVisionRagOpenRouterManualIT.java @@ -84,7 +84,7 @@ * */ @Tag("manual") -@EnabledIfSystemProperty(named = "manual.ollama.e2e", matches = "true") +@EnabledIfSystemProperty(named = "manual.openrouter.e2e", matches = "true") @SpringBootTest( classes = OpenRouterSimpleManualTestConfig.class, properties = "open-daimon.agent.enabled=false" diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/ObjectsImageVisionOpenRouterManualIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/ObjectsImageVisionOpenRouterManualIT.java index 8c91d0e9..dd50f2b5 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/ObjectsImageVisionOpenRouterManualIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/ObjectsImageVisionOpenRouterManualIT.java @@ -83,7 +83,7 @@ * */ @Tag("manual") -@EnabledIfSystemProperty(named = "manual.ollama.e2e", matches = "true") +@EnabledIfSystemProperty(named = "manual.openrouter.e2e", matches = "true") @SpringBootTest( classes = OpenRouterSimpleManualTestConfig.class, properties = "open-daimon.agent.enabled=false" diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/TextPdfRagOpenRouterManualIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/TextPdfRagOpenRouterManualIT.java index d29a7903..d300cc78 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/TextPdfRagOpenRouterManualIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/TextPdfRagOpenRouterManualIT.java @@ -79,7 +79,7 @@ * */ @Tag("manual") -@EnabledIfSystemProperty(named = "manual.ollama.e2e", matches = "true") +@EnabledIfSystemProperty(named = "manual.openrouter.e2e", matches = "true") @SpringBootTest( classes = OpenRouterSimpleManualTestConfig.class, properties = "open-daimon.agent.enabled=false" diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/XlsRagOpenRouterManualIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/XlsRagOpenRouterManualIT.java index c03312b1..c787db91 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/XlsRagOpenRouterManualIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/XlsRagOpenRouterManualIT.java @@ -87,7 +87,7 @@ * */ @Tag("manual") -@EnabledIfSystemProperty(named = "manual.ollama.e2e", matches = "true") +@EnabledIfSystemProperty(named = "manual.openrouter.e2e", matches = "true") @SpringBootTest( classes = OpenRouterSimpleManualTestConfig.class, properties = "open-daimon.agent.enabled=false" diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/support/ManualScenarioCache.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/support/ManualScenarioCache.java new file mode 100644 index 00000000..59825669 --- /dev/null +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/support/ManualScenarioCache.java @@ -0,0 +1,36 @@ +package io.github.ngirchev.opendaimon.it.manual.support; + +/** + * Lazily runs an expensive manual scenario once per test instance and reuses + * the captured result for assertions in multiple test methods. + */ +public final class ManualScenarioCache { + + private final ThrowingSupplier supplier; + private T value; + + private ManualScenarioCache(ThrowingSupplier supplier) { + this.supplier = supplier; + } + + public static ManualScenarioCache of(ThrowingSupplier supplier) { + return new ManualScenarioCache<>(supplier); + } + + public T get() throws Exception { + if (value == null) { + value = supplier.get(); + } + return value; + } + + public void clear() { + value = null; + } + + @FunctionalInterface + public interface ThrowingSupplier { + + T get() throws Exception; + } +} diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/support/ManualTelegramTestSupport.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/support/ManualTelegramTestSupport.java new file mode 100644 index 00000000..dafb21a9 --- /dev/null +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/support/ManualTelegramTestSupport.java @@ -0,0 +1,115 @@ +package io.github.ngirchev.opendaimon.it.manual.support; + +import io.github.ngirchev.opendaimon.common.model.Attachment; +import io.github.ngirchev.opendaimon.common.model.AttachmentType; +import io.github.ngirchev.opendaimon.common.model.ConversationThread; +import io.github.ngirchev.opendaimon.common.model.MessageRole; +import io.github.ngirchev.opendaimon.common.model.OpenDaimonMessage; +import io.github.ngirchev.opendaimon.common.repository.OpenDaimonMessageRepository; +import io.github.ngirchev.opendaimon.telegram.TelegramBot; +import io.github.ngirchev.opendaimon.telegram.command.TelegramCommand; +import io.github.ngirchev.opendaimon.telegram.command.TelegramCommandType; +import java.io.IOException; +import java.util.List; +import org.springframework.core.io.ClassPathResource; +import org.telegram.telegrambots.meta.api.objects.Chat; +import org.telegram.telegrambots.meta.api.objects.Message; +import org.telegram.telegrambots.meta.api.objects.Update; +import org.telegram.telegrambots.meta.api.objects.User; +import org.telegram.telegrambots.meta.api.objects.replykeyboard.ReplyKeyboard; +import org.telegram.telegrambots.meta.exceptions.TelegramApiException; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.reset; + +public final class ManualTelegramTestSupport { + + private ManualTelegramTestSupport() { + } + + public static void stubTelegramBot(TelegramBot telegramBot) throws TelegramApiException { + reset(telegramBot); + doNothing().when(telegramBot).showTyping(anyLong()); + doNothing().when(telegramBot).sendMessage(anyLong(), anyString(), any(), any(ReplyKeyboard.class)); + doNothing().when(telegramBot).sendMessage(anyLong(), anyString(), any()); + doNothing().when(telegramBot).sendErrorMessage(anyLong(), anyString(), any()); + } + + public static TelegramCommand createMessageCommand( + Long chatId, + int messageId, + String text, + String languageCode, + List attachments + ) { + Update update = new Update(); + + User from = new User(); + from.setId(chatId); + from.setUserName("manual-user-" + chatId); + from.setFirstName("Manual"); + from.setLastName("User"); + from.setLanguageCode(languageCode); + + Message message = new Message(); + message.setMessageId(messageId); + Chat chat = new Chat(); + chat.setId(chatId); + message.setChat(chat); + message.setFrom(from); + message.setText(text); + update.setMessage(message); + + TelegramCommand command = new TelegramCommand( + null, + chatId, + new TelegramCommandType(TelegramCommand.MESSAGE), + update, + text, + false, + attachments + ); + command.languageCode(languageCode); + return command; + } + + public static Attachment loadAttachment( + String resourcePath, + String contentType, + String originalFilename, + AttachmentType attachmentType + ) throws IOException { + ClassPathResource resource = new ClassPathResource(resourcePath); + byte[] bytes = resource.getInputStream().readAllBytes(); + return new Attachment( + "manual/" + originalFilename, + contentType, + originalFilename, + bytes.length, + attachmentType, + bytes + ); + } + + public static List assistantMessages( + ConversationThread thread, + OpenDaimonMessageRepository messageRepository + ) { + return messageRepository.findByThreadAndRoleOrderBySequenceNumberAsc(thread, MessageRole.ASSISTANT); + } + + public static String latestAssistantReply( + ConversationThread thread, + OpenDaimonMessageRepository messageRepository + ) { + List assistantMessages = assistantMessages(thread, messageRepository); + assertThat(assistantMessages) + .as("Assistant message should be saved") + .isNotEmpty(); + return assistantMessages.getLast().getContent(); + } +} diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/support/ManualTestPrerequisites.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/support/ManualTestPrerequisites.java new file mode 100644 index 00000000..d56d263b --- /dev/null +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/manual/support/ManualTestPrerequisites.java @@ -0,0 +1,68 @@ +package io.github.ngirchev.opendaimon.it.manual.support; + +import io.github.ngirchev.dotenv.DotEnvLoader; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.nio.file.Path; +import java.time.Duration; +import java.util.List; +import org.junit.jupiter.api.Assumptions; + +public final class ManualTestPrerequisites { + + private ManualTestPrerequisites() { + } + + public static void requireOpenRouterKey() { + DotEnvLoader.loadDotEnv(Path.of("../.env")); + String openRouterKey = System.getProperty("OPENROUTER_KEY", System.getenv("OPENROUTER_KEY")); + Assumptions.assumeTrue( + openRouterKey != null && !openRouterKey.isBlank() && !openRouterKey.equals("sk-placeholder"), + "Skipping manual test: OPENROUTER_KEY not set in .env or environment" + ); + } + + public static void requireSerperKey() { + DotEnvLoader.loadDotEnv(Path.of("../.env")); + String serperKey = System.getProperty("SERPER_KEY", System.getenv("SERPER_KEY")); + Assumptions.assumeTrue( + serperKey != null && !serperKey.isBlank(), + "Skipping manual test: SERPER_KEY not set in .env or environment" + ); + } + + public static void requireLocalOllamaWithModels(List requiredModels, Duration timeout) { + String baseUrl = resolveOllamaBaseUrl(); + HttpClient client = HttpClient.newBuilder() + .connectTimeout(timeout) + .build(); + HttpRequest request = HttpRequest.newBuilder() + .GET() + .timeout(timeout) + .uri(URI.create(baseUrl + "/api/tags")) + .build(); + try { + HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); + boolean statusOk = response.statusCode() == 200; + boolean modelsPresent = requiredModels.stream().allMatch(response.body()::contains); + Assumptions.assumeTrue(statusOk && modelsPresent, + "Skipping manual test: Ollama/models unavailable at " + baseUrl + ". Required: " + requiredModels); + } catch (Exception ex) { + Assumptions.assumeTrue(false, + "Skipping manual test: cannot connect to Ollama at " + baseUrl + ". " + ex.getMessage()); + } + } + + public static String resolveOllamaBaseUrl() { + String baseUrl = System.getenv("OLLAMA_BASE_URL"); + if (baseUrl == null || baseUrl.isBlank()) { + baseUrl = "http://localhost:11434"; + } + if (baseUrl.endsWith("/")) { + return baseUrl.substring(0, baseUrl.length() - 1); + } + return baseUrl; + } +} diff --git a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/telegram/TelegramRealGatewayIT.java b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/telegram/TelegramRealGatewayIT.java index 9857e8ef..2b6c0cca 100644 --- a/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/telegram/TelegramRealGatewayIT.java +++ b/opendaimon-app/src/it/java/io/github/ngirchev/opendaimon/it/telegram/TelegramRealGatewayIT.java @@ -50,7 +50,7 @@ * *

To run the test: *

    - *
  1. Ensure .env contains TELEGRAM_TOKEN, TELEGRAM_USERNAME and ADMIN_TELEGRAM_ID
  2. + *
  3. Ensure .env contains TELEGRAM_TOKEN, TELEGRAM_USERNAME and TEST_TELEGRAM_CHAT_ID
  4. *
  5. Remove @Disabled from the test or the whole class
  6. *
  7. Run the test
  8. *
@@ -84,7 +84,7 @@ class TelegramRealGatewayIT extends AbstractContainerIT { DotEnvLoader.loadDotEnv(Path.of("../.env")); } - @Value("${ADMIN_TELEGRAM_ID}") + @Value("${TEST_TELEGRAM_CHAT_ID}") private Long adminTelegramId; @Autowired diff --git a/opendaimon-app/src/main/resources/application-mock.yml b/opendaimon-app/src/main/resources/application-mock.yml index b0f34b11..0ecc22f1 100644 --- a/opendaimon-app/src/main/resources/application-mock.yml +++ b/opendaimon-app/src/main/resources/application-mock.yml @@ -15,10 +15,6 @@ open-daimon: REGULAR: maxConcurrentCalls: 1 maxWaitDuration: 500ms - admin: - enabled: ${ADMIN_ENABLED:true} - telegram-id: ${ADMIN_TELEGRAM_ID:} - rest-email: ${ADMIN_REST_EMAIL:} assistant-role: role.content.default max-output-tokens: 1000 max-user-message-tokens: 4000 diff --git a/opendaimon-app/src/main/resources/application.yml b/opendaimon-app/src/main/resources/application.yml index 10602676..b8fc93c2 100644 --- a/opendaimon-app/src/main/resources/application.yml +++ b/opendaimon-app/src/main/resources/application.yml @@ -1,3 +1,8 @@ +# Bundled OpenDaimon runtime keeps its effective configuration explicit in this file. +# Reference only: external apps that use opendaimon-spring-boot-starter receive low-priority defaults from: +# opendaimon-spring-boot-starter/src/main/resources/META-INF/opendaimon/opendaimon-defaults.yml +# This app does not depend on the starter and does not import those defaults, so change runtime values here. + server: port: 8080 @@ -23,10 +28,6 @@ open-daimon: REGULAR: maxConcurrentCalls: 1 maxWaitDuration: 500ms - admin: - enabled: ${ADMIN_ENABLED:true} - telegram-id: ${ADMIN_TELEGRAM_ID:} - rest-email: ${ADMIN_REST_EMAIL:} assistant-role: role.content.default # Hard limit for entire prompt to API (system + history + current). When exceeded — trim/reject and return error. max-total-prompt-tokens: 32000 @@ -190,6 +191,7 @@ open-daimon: - stepfun/step-3.5-flash:free blacklist: exclude-model-ids: [] # add model IDs here to block them permanently + exclude-contains: [] # add substrings here to block model families ranking: enabled: true retry-max-attempts: 3 diff --git a/opendaimon-common/pom.xml b/opendaimon-common/pom.xml index 56148ebc..7d474768 100644 --- a/opendaimon-common/pom.xml +++ b/opendaimon-common/pom.xml @@ -116,6 +116,11 @@ org.flywaydb flyway-core + + org.flywaydb + flyway-database-postgresql + runtime + @@ -263,6 +268,8 @@ com.tngtech.archunit:archunit-junit5-engine + + org.flywaydb:flyway-database-postgresql diff --git a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/config/CoreAutoConfig.java b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/config/CoreAutoConfig.java index c20d23ec..dbae688d 100644 --- a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/config/CoreAutoConfig.java +++ b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/config/CoreAutoConfig.java @@ -1,6 +1,7 @@ package io.github.ngirchev.opendaimon.common.config; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfigureAfter; @@ -276,6 +277,12 @@ public SummarizationService summarizationService( ); } + @Bean + @ConditionalOnMissingBean + public MeterRegistry meterRegistry() { + return new SimpleMeterRegistry(); + } + @Bean @ConditionalOnMissingBean public OpenDaimonMeterRegistry openDaimonMeterRegistry(MeterRegistry meterRegistry) { diff --git a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/config/CoreCommonProperties.java b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/config/CoreCommonProperties.java index 1f5e2f08..90b94125 100644 --- a/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/config/CoreCommonProperties.java +++ b/opendaimon-common/src/main/java/io/github/ngirchev/opendaimon/common/config/CoreCommonProperties.java @@ -68,13 +68,6 @@ public boolean isMaxReasoningTokensValid() { @NestedConfigurationProperty private SummarizationProperties summarization = new SummarizationProperties(); - /** - * Admin initialization at application startup. - */ - @Valid - @NestedConfigurationProperty - private AdminProperties admin = new AdminProperties(); - /** * AI command routing by user priority. YAML uses {@code ADMIN} / {@code VIP} / {@code REGULAR} keys * (same style as {@code open-daimon.telegram.access}); Java fields are {@code admin}, {@code vip}, {@code regular}. @@ -135,30 +128,6 @@ public static class SummarizationProperties { private String prompt; } - /** - * Admin configuration properties. - */ - @Getter - @Setter - @Validated - public static class AdminProperties { - - /** - * Whether to run admin initialization. - */ - private Boolean enabled = false; - - /** - * Admin Telegram ID (optional). - */ - private Long telegramId; - - /** - * Admin REST email (optional). - */ - private String restEmail; - } - /** * Nested {@code ADMIN} / {@code VIP} / {@code REGULAR} blocks under {@code open-daimon.common.chat-routing}. */ @@ -214,4 +183,4 @@ public static class PriorityChatRoutingProperties { @NotNull(message = "optionalCapabilities is required") private List optionalCapabilities; } -} \ No newline at end of file +} diff --git a/opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/common/config/CoreAutoConfigMeterRegistryTest.java b/opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/common/config/CoreAutoConfigMeterRegistryTest.java new file mode 100644 index 00000000..ee691c43 --- /dev/null +++ b/opendaimon-common/src/test/java/io/github/ngirchev/opendaimon/common/config/CoreAutoConfigMeterRegistryTest.java @@ -0,0 +1,22 @@ +package io.github.ngirchev.opendaimon.common.config; + +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import io.github.ngirchev.opendaimon.common.meter.OpenDaimonMeterRegistry; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import org.junit.jupiter.api.Test; + +class CoreAutoConfigMeterRegistryTest { + + @Test + void createsSimpleMeterRegistryFallbackForConsumersWithoutActuator() { + CoreAutoConfig autoConfig = new CoreAutoConfig(); + + var meterRegistry = autoConfig.meterRegistry(); + OpenDaimonMeterRegistry openDaimonMeterRegistry = autoConfig.openDaimonMeterRegistry(meterRegistry); + + assertInstanceOf(SimpleMeterRegistry.class, meterRegistry); + assertNotNull(openDaimonMeterRegistry); + } +} diff --git a/opendaimon-rest/pom.xml b/opendaimon-rest/pom.xml index 79331371..617aabb2 100644 --- a/opendaimon-rest/pom.xml +++ b/opendaimon-rest/pom.xml @@ -38,6 +38,10 @@ + + org.springframework + spring-beans + org.springframework spring-context diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/config/RestAutoConfig.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/config/RestAutoConfig.java index dae3c67b..305a5f57 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/config/RestAutoConfig.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/config/RestAutoConfig.java @@ -1,6 +1,7 @@ package io.github.ngirchev.opendaimon.rest.config; import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -180,8 +181,8 @@ public AdminQueryService adminQueryService( @ConditionalOnMissingBean public AdminAttachmentService adminAttachmentService( OpenDaimonMessageRepository messageRepository, - FileStorageService fileStorageService) { - return new AdminAttachmentService(messageRepository, fileStorageService); + ObjectProvider fileStorageServiceProvider) { + return new AdminAttachmentService(messageRepository, fileStorageServiceProvider.getIfAvailable()); } @Bean @@ -208,4 +209,3 @@ public AdminMeController adminMeController() { return new AdminMeController(); } } - diff --git a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/AdminAttachmentService.java b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/AdminAttachmentService.java index 77acacc8..c6b6d300 100644 --- a/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/AdminAttachmentService.java +++ b/opendaimon-rest/src/main/java/io/github/ngirchev/opendaimon/rest/service/AdminAttachmentService.java @@ -37,6 +37,10 @@ public Optional resolve(Long messageId, String storageKey) { if (messageId == null || storageKey == null || storageKey.isBlank()) { return Optional.empty(); } + if (fileStorageService == null) { + log.warn("Admin requested attachment storageKey={} but file storage is disabled", storageKey); + return Optional.empty(); + } Optional messageOpt = messageRepository.findById(messageId); if (messageOpt.isEmpty()) { log.warn("Admin requested attachment for unknown messageId={}", messageId); diff --git a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/service/AdminAttachmentServiceTest.java b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/service/AdminAttachmentServiceTest.java index 0a92a767..dba963d2 100644 --- a/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/service/AdminAttachmentServiceTest.java +++ b/opendaimon-rest/src/test/java/io/github/ngirchev/opendaimon/rest/service/AdminAttachmentServiceTest.java @@ -101,6 +101,16 @@ void shouldReturnEmptyWhenStorageLookupFails() { assertThat(resolved).isEmpty(); } + @Test + void shouldReturnEmptyWhenStorageIsDisabled() { + service = new AdminAttachmentService(messageRepository, null); + + Optional resolved = service.resolve(42L, "abc123"); + + assertThat(resolved).isEmpty(); + verify(messageRepository, never()).findById(org.mockito.ArgumentMatchers.anyLong()); + } + @Test void shouldFallbackDefaultMimeWhenMissing() { OpenDaimonMessage message = messageWithAttachments(List.of( diff --git a/opendaimon-spring-ai/SPRING_AI_MODULE.md b/opendaimon-spring-ai/SPRING_AI_MODULE.md index 023d7417..3ff997a8 100644 --- a/opendaimon-spring-ai/SPRING_AI_MODULE.md +++ b/opendaimon-spring-ai/SPRING_AI_MODULE.md @@ -101,6 +101,8 @@ If `springAiProperties.mock = true` → return mock response immediately, no mod Web tools (`WebTools` / Serper) are attached to the prompt when: - command requests `WEB` in **required** (`modelCapabilities`) or **optional** (`optionalCapabilities`). +- `web_search` is disabled when `open-daimon.ai.spring-ai.serper.api.key` is blank; + in that case it returns an empty search result without calling Serper. --- diff --git a/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/config/SpringAIProperties.java b/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/config/SpringAIProperties.java index 065a50ad..ce7e30d2 100644 --- a/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/config/SpringAIProperties.java +++ b/opendaimon-spring-ai/src/main/java/io/github/ngirchev/opendaimon/ai/springai/config/SpringAIProperties.java @@ -28,8 +28,6 @@ public class SpringAIProperties { */ private OpenRouterApp openrouterApp = new OpenRouterApp(); - private HttpLogs httpLogs = new HttpLogs(); - private Serper serper = new Serper(); private Models models = new Models(); @@ -116,7 +114,6 @@ public static class Serper { @Getter @Setter public static class Api { - @NotBlank(message = "API key for Serper cannot be blank") private String key; @NotBlank(message = "Serper API URL cannot be blank") @@ -131,16 +128,6 @@ public static class Models { private List list = new ArrayList<>(); } - @Getter - @Setter - public static class HttpLogs { - /** - * Log call stack of "who made the AI HTTP request" (once at startup). - * Disabled by default as it looks like an exception in logs and is noisy. - */ - private Boolean callsiteStacktraceEnabled = false; - } - private Timeouts timeouts = new Timeouts(); @Getter diff --git a/opendaimon-spring-boot-starter/pom.xml b/opendaimon-spring-boot-starter/pom.xml new file mode 100644 index 00000000..6d1a1fd9 --- /dev/null +++ b/opendaimon-spring-boot-starter/pom.xml @@ -0,0 +1,84 @@ + + + + 4.0.0 + + io.github.ngirchev + opendaimon + 1.0.0-SNAPSHOT + + + opendaimon-spring-boot-starter + OpenDaimon Spring Boot Starter + + + 21 + 21 + 21 + + UTF-8 + UTF-8 + + + + + + io.github.ngirchev + opendaimon-common + ${project.version} + + + io.github.ngirchev + opendaimon-spring-ai + ${project.version} + + + + + org.springframework.boot + spring-boot + + + org.springframework + spring-core + + + + + org.junit.jupiter + junit-jupiter-api + test + + + org.assertj + assertj-core + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + io.github.ngirchev:opendaimon-common + io.github.ngirchev:opendaimon-spring-ai + + + + + + diff --git a/opendaimon-spring-boot-starter/src/main/java/io/github/ngirchev/opendaimon/starter/OpenDaimonDefaultsEnvironmentPostProcessor.java b/opendaimon-spring-boot-starter/src/main/java/io/github/ngirchev/opendaimon/starter/OpenDaimonDefaultsEnvironmentPostProcessor.java new file mode 100644 index 00000000..ffd58f1f --- /dev/null +++ b/opendaimon-spring-boot-starter/src/main/java/io/github/ngirchev/opendaimon/starter/OpenDaimonDefaultsEnvironmentPostProcessor.java @@ -0,0 +1,40 @@ +package io.github.ngirchev.opendaimon.starter; + +import java.io.IOException; +import java.io.UncheckedIOException; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.env.EnvironmentPostProcessor; +import org.springframework.boot.env.YamlPropertySourceLoader; +import org.springframework.core.Ordered; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.io.ClassPathResource; + +public final class OpenDaimonDefaultsEnvironmentPostProcessor implements EnvironmentPostProcessor, Ordered { + + static final String DEFAULTS_RESOURCE = "META-INF/opendaimon/opendaimon-defaults.yml"; + private static final String DEFAULTS_PROPERTY_SOURCE_NAME = "opendaimon-defaults"; + + @Override + public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) { + if (environment.getPropertySources().contains(DEFAULTS_PROPERTY_SOURCE_NAME)) { + return; + } + + try { + var resource = new ClassPathResource(DEFAULTS_RESOURCE); + var loader = new YamlPropertySourceLoader(); + var propertySources = loader.load(DEFAULTS_PROPERTY_SOURCE_NAME, resource); + for (var propertySource : propertySources.reversed()) { + environment.getPropertySources().addLast(propertySource); + } + } catch (IOException e) { + throw new UncheckedIOException("Failed to load OpenDaimon starter defaults", e); + } + } + + @Override + public int getOrder() { + return Ordered.LOWEST_PRECEDENCE; + } +} diff --git a/opendaimon-spring-boot-starter/src/main/resources/META-INF/opendaimon/opendaimon-defaults.yml b/opendaimon-spring-boot-starter/src/main/resources/META-INF/opendaimon/opendaimon-defaults.yml new file mode 100644 index 00000000..9719a07a --- /dev/null +++ b/opendaimon-spring-boot-starter/src/main/resources/META-INF/opendaimon/opendaimon-defaults.yml @@ -0,0 +1,156 @@ +spring: + ai: + ollama: + base-url: ${OLLAMA_BASE_URL:http://localhost:11434} + request-timeout: 600s + openai: + base-url: https://openrouter.ai/api + chat: + memory: + repository: + jdbc: + initialize-schema: never + +open-daimon: + common: + storage: + enabled: false + minio: + endpoint: ${MINIO_ENDPOINT:http://localhost:9000} + access-key: ${MINIO_USER:minioadmin} + secret-key: ${MINIO_PASSWORD:minioadmin} + bucket: opendaimon-files + ttl-hours: 24 + bulkhead: + enabled: false + instances: + ADMIN: + maxConcurrentCalls: 10 + maxWaitDuration: 1s + VIP: + maxConcurrentCalls: 5 + maxWaitDuration: 1s + REGULAR: + maxConcurrentCalls: 1 + maxWaitDuration: 500ms + assistant-role: role.content.default + max-total-prompt-tokens: 32000 + max-user-message-tokens: 4000 + max-output-tokens: 4000 + max-reasoning-tokens: 1500 + chat-routing: + ADMIN: + max-price: 5.0 + required-capabilities: + - AUTO + optional-capabilities: [] + VIP: + max-price: 0.5 + required-capabilities: + - CHAT + optional-capabilities: + - TOOL_CALLING + - WEB + REGULAR: + max-price: ${OPENDAIMON_REGULAR_MAX_PRICE:5.0} + required-capabilities: + - CHAT + optional-capabilities: [] + summarization: + message-window-size: 50 + max-window-tokens: 16000 + max-output-tokens: 6000 + prompt: | + You are summarizing a conversation for an AI assistant's long-term memory. + If a "Previous conversation summary" section is present, incorporate it into your new summary - produce a SINGLE UNIFIED summary, not a continuation. + + Rules: + 1. Summarize only what was ACTUALLY said - do not infer, interpret, or invent meaning. If messages are trivial (e.g. single words, numbers, test messages), state that plainly. + 2. Summary: 2-4 paragraphs, max 500 words. Focus on user's goals, decisions made, problems solved, preferences expressed. + 3. Memory bullets: up to 10 key facts the assistant must remember going forward. Omit bullets if there is nothing meaningful to remember. + 4. If previous bullets exist, keep relevant ones, drop obsolete, deduplicate. + 5. Respond in the SAME LANGUAGE as the conversation. + 6. Reply in strict JSON only (no markdown, no backticks, no preamble): + {"summary": "...", "memory_bullets": ["fact 1", "fact 2", ...]} + + Conversation: + ai: + spring-ai: + enabled: true + openrouter-app: + site-url: ${OPENROUTER_APP_SITE_URL:} + title: ${OPENROUTER_APP_TITLE:} + openrouter-auto-rotation: + models: + enabled: false + api: + key: ${OPENROUTER_KEY:} + url: https://openrouter.ai/api + refresh-initial-delay: 10s + refresh-interval: 24h + whitelist: [] + blacklist: + exclude-model-ids: [] + exclude-contains: [] + ranking: + enabled: true + retry-max-attempts: 3 + latency-ewma-alpha: 0.2 + cooldown429: 10m + cooldown5xx: 5m + cooldown404: 6h + serper: + api: + url: https://google.serper.dev/search + key: ${SERPER_KEY:} + mock: false + timeouts: + response-timeout-seconds: 600 + url-check: + enabled: true + timeout-ms: 3000 + max-urls-per-answer: 10 + cache-ttl-minutes: 10 + ssl: + merge-system-keychain: true + models: + list: + - name: ${OPENDAIMON_DEFAULT_MODEL:${OPENROUTER_CONTRACT_MODEL:openrouter/auto}} + provider-type: ${OPENDAIMON_DEFAULT_PROVIDER:OPENAI} + priority: 1 + capabilities: + - AUTO + - CHAT + - TOOL_CALLING + - WEB + - SUMMARIZATION + - VISION + allowed-roles: + - ADMIN + - VIP + - REGULAR + rag: + enabled: false + chunk-size: 800 + chunk-overlap: 100 + top-k: 5 + similarity-threshold: 0.7 + prompts: + document-extract-error-pdf: "Could not extract text from file \"%s\". The file may be a scanned/image-only PDF or corrupted." + document-extract-error-document: "Could not extract text from file \"%s\" (type: %s). The file may be unsupported or corrupted." + augmented-prompt-template: | + The user attached one or more documents. The following context was extracted from them. + + Context: + %s + + User question: + %s + vision-extraction-prompt: "Extract ALL text content from this image exactly as written. Include all headings, paragraphs, tables, lists, captions, and any visible text. Preserve the original structure and formatting as much as possible. Output only the extracted text, no commentary." + agent: + enabled: true + max-iterations: 10 + stream-timeout-seconds: 600 + tools: + http-api: + enabled: true diff --git a/opendaimon-spring-boot-starter/src/main/resources/META-INF/spring.factories b/opendaimon-spring-boot-starter/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..584d1f78 --- /dev/null +++ b/opendaimon-spring-boot-starter/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.env.EnvironmentPostProcessor=\ +io.github.ngirchev.opendaimon.starter.OpenDaimonDefaultsEnvironmentPostProcessor diff --git a/opendaimon-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/opendaimon-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 00000000..46d9bd04 --- /dev/null +++ b/opendaimon-spring-boot-starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1,6 @@ +io.github.ngirchev.opendaimon.common.config.CoreAutoConfig +io.github.ngirchev.opendaimon.bulkhead.config.BulkHeadAutoConfig +io.github.ngirchev.opendaimon.common.storage.config.StorageAutoConfig +io.github.ngirchev.opendaimon.ai.springai.config.SpringAIAutoConfig +io.github.ngirchev.opendaimon.ai.springai.config.RAGAutoConfig +io.github.ngirchev.opendaimon.ai.springai.config.AgentAutoConfig diff --git a/opendaimon-spring-boot-starter/src/test/java/io/github/ngirchev/opendaimon/starter/OpenDaimonDefaultsEnvironmentPostProcessorTest.java b/opendaimon-spring-boot-starter/src/test/java/io/github/ngirchev/opendaimon/starter/OpenDaimonDefaultsEnvironmentPostProcessorTest.java new file mode 100644 index 00000000..4a95f73e --- /dev/null +++ b/opendaimon-spring-boot-starter/src/test/java/io/github/ngirchev/opendaimon/starter/OpenDaimonDefaultsEnvironmentPostProcessorTest.java @@ -0,0 +1,74 @@ +package io.github.ngirchev.opendaimon.starter; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.util.Map; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.SpringApplication; +import org.springframework.core.env.MapPropertySource; +import org.springframework.core.env.StandardEnvironment; + +class OpenDaimonDefaultsEnvironmentPostProcessorTest { + + private static final String SPRING_FACTORIES_RESOURCE = "META-INF/spring.factories"; + + @Test + void shouldRegisterEnvironmentPostProcessorInSpringFactories() { + assertThat(loadResource(SPRING_FACTORIES_RESOURCE)) + .contains("org.springframework.boot.env.EnvironmentPostProcessor") + .contains(OpenDaimonDefaultsEnvironmentPostProcessor.class.getName()); + } + + @Test + void shouldLoadStarterDefaultsAtLowestPrecedence() { + var environment = new StandardEnvironment(); + environment.getPropertySources().addFirst(new MapPropertySource( + "consumer-application", + Map.of( + "open-daimon.common.max-output-tokens", 1234, + "open-daimon.agent.max-iterations", 2))); + + new OpenDaimonDefaultsEnvironmentPostProcessor() + .postProcessEnvironment(environment, new SpringApplication(Object.class)); + + assertThat(environment.getProperty("open-daimon.ai.spring-ai.enabled", Boolean.class)) + .isTrue(); + assertThat(environment.getProperty("open-daimon.common.storage.enabled", Boolean.class)) + .isFalse(); + assertThat(environment.getProperty("open-daimon.common.bulkhead.enabled", Boolean.class)) + .isFalse(); + assertThat(environment.getProperty("open-daimon.ai.spring-ai.rag.enabled", Boolean.class)) + .isFalse(); + assertThat(environment.getProperty("open-daimon.agent.enabled", Boolean.class)) + .isTrue(); + assertThat(environment.getProperty("spring.ai.openai.base-url")) + .isEqualTo("https://openrouter.ai/api"); + assertThat(environment.getProperty("open-daimon.ai.spring-ai.url-check.enabled", Boolean.class)) + .isTrue(); + assertThat(environment.getProperty("open-daimon.ai.spring-ai.serper.api.key")) + .isEmpty(); + assertThat(environment.getProperty("open-daimon.ai.spring-ai.models.list[0].capabilities[0]")) + .isEqualTo("AUTO"); + assertThat(environment.getProperty("open-daimon.common.max-output-tokens", Integer.class)) + .isEqualTo(1234); + assertThat(environment.getProperty("open-daimon.agent.max-iterations", Integer.class)) + .isEqualTo(2); + assertThat(environment.containsProperty("open-daimon.rest.enabled")) + .isFalse(); + } + + private String loadResource(String resourceName) { + try (var input = Thread.currentThread() + .getContextClassLoader() + .getResourceAsStream(resourceName)) { + assertThat(input).as(resourceName).isNotNull(); + return new String(input.readAllBytes(), StandardCharsets.UTF_8); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/opendaimon-spring-boot-starter/src/test/java/io/github/ngirchev/opendaimon/starter/OpenDaimonStarterAutoConfigurationImportsTest.java b/opendaimon-spring-boot-starter/src/test/java/io/github/ngirchev/opendaimon/starter/OpenDaimonStarterAutoConfigurationImportsTest.java new file mode 100644 index 00000000..e64170bd --- /dev/null +++ b/opendaimon-spring-boot-starter/src/test/java/io/github/ngirchev/opendaimon/starter/OpenDaimonStarterAutoConfigurationImportsTest.java @@ -0,0 +1,46 @@ +package io.github.ngirchev.opendaimon.starter; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.charset.StandardCharsets; +import java.util.List; + +import org.junit.jupiter.api.Test; + +class OpenDaimonStarterAutoConfigurationImportsTest { + + private static final String IMPORTS_RESOURCE = + "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports"; + + @Test + void shouldExposeCommonAndSpringAiAutoConfigurations() { + assertThat(loadAutoConfigurationImports()) + .containsExactly( + "io.github.ngirchev.opendaimon.common.config.CoreAutoConfig", + "io.github.ngirchev.opendaimon.bulkhead.config.BulkHeadAutoConfig", + "io.github.ngirchev.opendaimon.common.storage.config.StorageAutoConfig", + "io.github.ngirchev.opendaimon.ai.springai.config.SpringAIAutoConfig", + "io.github.ngirchev.opendaimon.ai.springai.config.RAGAutoConfig", + "io.github.ngirchev.opendaimon.ai.springai.config.AgentAutoConfig"); + } + + private List loadAutoConfigurationImports() { + try (var input = Thread.currentThread() + .getContextClassLoader() + .getResourceAsStream(IMPORTS_RESOURCE)) { + assertThat(input).as("starter auto-configuration imports resource").isNotNull(); + + var content = new String(input.readAllBytes(), StandardCharsets.UTF_8); + + return content.lines() + .map(String::trim) + .filter(line -> !line.isEmpty()) + .filter(line -> !line.startsWith("#")) + .toList(); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } +} diff --git a/opendaimon-starter-consumer-example/README.md b/opendaimon-starter-consumer-example/README.md new file mode 100644 index 00000000..c8910024 --- /dev/null +++ b/opendaimon-starter-consumer-example/README.md @@ -0,0 +1,70 @@ +# OpenDaimon Starter Consumer Example + +This is a standalone Maven project that simulates an external Spring Boot application consuming OpenDaimon through the starter. + +It is intentionally not listed in the root `pom.xml` modules and is not part of the published OpenDaimon reactor. + +The example declares two OpenDaimon dependencies: + +```xml + + io.github.ngirchev + opendaimon-spring-boot-starter + ${open-daimon.version} + + + io.github.ngirchev + opendaimon-rest + ${open-daimon.version} + +``` + +The starter brings the common and Spring AI modules, auto-configuration imports, and low-priority OpenDaimon defaults from `META-INF/opendaimon/opendaimon-defaults.yml`. `opendaimon-rest` is declared separately because REST API delivery is optional and is not part of the minimal starter dependency set. + +Starter defaults, overrideable from the consumer application's own configuration: + +- `open-daimon.ai.spring-ai.enabled=true` +- `open-daimon.agent.enabled=true` +- safe defaults for common token limits, summarization, storage, bulkhead, and priority routing +- Spring AI sample: OpenRouter-compatible OpenAI provider with `openrouter/auto` +- Spring AI provider endpoint: `spring.ai.openai.base-url=https://openrouter.ai/api` +- Spring AI defaults for OpenRouter auto-rotation, Serper, URL checking, SSL, RAG, and agent settings +- infrastructure-backed features are disabled by default where enabling them would require extra services or optional dependencies: storage, bulkhead, RAG, and OpenRouter model rotation +- Optional overrides: `OPENDAIMON_DEFAULT_MODEL`, `OPENDAIMON_DEFAULT_PROVIDER`, and `OPENROUTER_CONTRACT_MODEL` + +Included OpenDaimon configuration in `src/main/resources/application.yml`: + +- REST opt-in: `open-daimon.rest.enabled=true` +- REST access sample: `admin@example.com` and `user@example.com` + +The consumer application provides regular Spring Boot infrastructure dependencies (`spring-boot-starter-web`, `spring-boot-starter-data-jpa`, `spring-boot-starter-validation`, and PostgreSQL JDBC). It also calls `DotEnvLoader.loadDotEnv()` on startup, so secrets such as `OPENROUTER_KEY`, `SPRING_DATASOURCE_URL`, `SPRING_DATASOURCE_USERNAME`, or `SPRING_DATASOURCE_PASSWORD` can be kept in a local `.env` file. At runtime it expects PostgreSQL and OpenRouter unless you replace those settings. + +For local PostgreSQL the example accepts standard Spring Boot datasource variables: + +```properties +SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/opendaimon +SPRING_DATASOURCE_USERNAME=postgres +SPRING_DATASOURCE_PASSWORD=postgres +``` + +If PostgreSQL reports `password authentication failed`, make these values match the credentials used when the local `open-daimon-postgres` container or database was first created. + +Run it against locally installed snapshots: + +```bash +./mvnw -pl opendaimon-spring-boot-starter,opendaimon-rest -am install -DskipTests -DskipITs -DskipIT +mvn -f opendaimon-starter-consumer-example/pom.xml test +``` + +The smoke test verifies that Spring Boot can discover OpenDaimon auto-configuration candidates from the consumer classpath without manually importing OpenDaimon configuration, that starter defaults for Spring AI are present on the classpath, and that REST is enabled by the consumer application because `opendaimon-rest` is an explicit dependency. + +The example also contains a manual-only contract test that starts a PostgreSQL Testcontainer, boots the REST API, sends a chat-style request to `/api/v1/session`, and expects the answer to come from real OpenRouter: + +```bash +mvn -f opendaimon-starter-consumer-example/pom.xml verify \ + -DskipITs=false \ + -Dit.test=OpenRouterRestContractIT \ + -Dmanual.openrouter.rest-contract=true +``` + +The contract test loads `.env` from the repository root and from `opendaimon-starter-consumer-example/.env`. It requires Docker, outbound network access, and `OPENROUTER_KEY`; `OPENROUTER_CONTRACT_MODEL` is optional and defaults to `openrouter/auto`. diff --git a/opendaimon-starter-consumer-example/pom.xml b/opendaimon-starter-consumer-example/pom.xml new file mode 100644 index 00000000..b417c295 --- /dev/null +++ b/opendaimon-starter-consumer-example/pom.xml @@ -0,0 +1,144 @@ + + + 4.0.0 + + io.github.ngirchev.opendaimon.examples + opendaimon-starter-consumer-example + 1.0.0-SNAPSHOT + + OpenDaimon Starter Consumer Example + Standalone consumer smoke test for the OpenDaimon Spring Boot starter. + + + 21 + 21 + 21 + + 1.0.0-SNAPSHOT + 3.5.13 + 1.21.4 + 1.0.5 + + 3.11.0 + 3.2.5 + 3.2.5 + true + + UTF-8 + UTF-8 + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + org.testcontainers + testcontainers-bom + ${testcontainers.version} + pom + import + + + + + + + io.github.ngirchev + opendaimon-spring-boot-starter + ${open-daimon.version} + + + io.github.ngirchev + opendaimon-rest + ${open-daimon.version} + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-validation + + + + org.postgresql + postgresql + runtime + + + + io.github.ngirchev + dotenv + ${dotenv.version} + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.testcontainers + junit-jupiter + test + + + org.testcontainers + postgresql + test + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + ${java.version} + ${java.version} + true + + + + org.apache.maven.plugins + maven-surefire-plugin + ${maven-surefire-plugin.version} + + + org.apache.maven.plugins + maven-failsafe-plugin + ${maven-failsafe-plugin.version} + + + + integration-test + verify + + + + + ${skipITs} + + **/*IT.java + + + + + + diff --git a/opendaimon-starter-consumer-example/src/main/java/io/github/ngirchev/opendaimon/example/StarterConsumerApplication.java b/opendaimon-starter-consumer-example/src/main/java/io/github/ngirchev/opendaimon/example/StarterConsumerApplication.java new file mode 100644 index 00000000..01172888 --- /dev/null +++ b/opendaimon-starter-consumer-example/src/main/java/io/github/ngirchev/opendaimon/example/StarterConsumerApplication.java @@ -0,0 +1,14 @@ +package io.github.ngirchev.opendaimon.example; + +import io.github.ngirchev.dotenv.DotEnvLoader; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StarterConsumerApplication { + + public static void main(String[] args) { + DotEnvLoader.loadDotEnv(); + SpringApplication.run(StarterConsumerApplication.class, args); + } +} diff --git a/opendaimon-starter-consumer-example/src/main/resources/application.yml b/opendaimon-starter-consumer-example/src/main/resources/application.yml new file mode 100644 index 00000000..28220b1b --- /dev/null +++ b/opendaimon-starter-consumer-example/src/main/resources/application.yml @@ -0,0 +1,25 @@ +spring: + application: + name: opendaimon-starter-consumer-example + datasource: + url: ${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/opendaimon} + username: ${SPRING_DATASOURCE_USERNAME:postgres} + password: ${SPRING_DATASOURCE_PASSWORD:postgres} + jpa: + hibernate: + ddl-auto: validate + open-in-view: false + ai: + openai: + api-key: ${OPENROUTER_KEY:missing-openrouter-key} + +open-daimon: + rest: + enabled: true + access: + admin: + emails: + - ${OPENDAIMON_ADMIN_EMAIL:admin@example.com} + regular: + emails: + - ${OPENDAIMON_USER_EMAIL:user@example.com} diff --git a/opendaimon-starter-consumer-example/src/test/java/io/github/ngirchev/opendaimon/example/OpenRouterRestContractManualIT.java b/opendaimon-starter-consumer-example/src/test/java/io/github/ngirchev/opendaimon/example/OpenRouterRestContractManualIT.java new file mode 100644 index 00000000..a3c565b8 --- /dev/null +++ b/opendaimon-starter-consumer-example/src/test/java/io/github/ngirchev/opendaimon/example/OpenRouterRestContractManualIT.java @@ -0,0 +1,84 @@ +package io.github.ngirchev.opendaimon.example; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +import java.nio.file.Path; + +import com.fasterxml.jackson.databind.JsonNode; +import io.github.ngirchev.dotenv.DotEnvLoader; +import io.github.ngirchev.opendaimon.rest.dto.ChatRequestDto; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.util.StringUtils; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +@Testcontainers +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@Tag("manual") +@EnabledIfSystemProperty(named = "manual.openrouter.rest-contract", matches = "true") +class OpenRouterRestContractManualIT { + + private static final String OPENROUTER_KEY = "OPENROUTER_KEY"; + private static final String ADMIN_EMAIL = "admin@example.com"; + + @Container + static final PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:16-alpine"); + + static { + DotEnvLoader.loadDotEnv(Path.of("..", ".env")); + DotEnvLoader.loadDotEnv(); + } + + @Autowired + private TestRestTemplate restTemplate; + + @DynamicPropertySource + static void registerProperties(DynamicPropertyRegistry registry) { + registry.add("spring.datasource.url", postgres::getJdbcUrl); + registry.add("spring.datasource.username", postgres::getUsername); + registry.add("spring.datasource.password", postgres::getPassword); + registry.add("spring.ai.openai.api-key", OpenRouterRestContractManualIT::openRouterKeyOrPlaceholder); + } + + @Test + void restChatEndpointUsesRealOpenRouterProvider() { + assumeTrue(StringUtils.hasText(openRouterKey()), "OPENROUTER_KEY is required for the OpenRouter contract test"); + + var request = new ChatRequestDto( + "What is 2 + 2? Reply with only the digit 4.", + null, + null, + ADMIN_EMAIL); + + var response = restTemplate.postForEntity("/api/v1/session", request, JsonNode.class); + + assertThat(response.getStatusCode()) + .as(() -> response.getBody() != null ? response.getBody().toPrettyString() : "empty response body") + .isEqualTo(HttpStatus.OK); + assertThat(response.getBody()) + .isNotNull(); + assertThat(response.getBody().path("sessionId").asText()) + .isNotBlank(); + assertThat(response.getBody().path("message").asText()) + .contains("4"); + } + + private static String openRouterKeyOrPlaceholder() { + String key = openRouterKey(); + return StringUtils.hasText(key) ? key : "missing-openrouter-key"; + } + + private static String openRouterKey() { + return DotEnvLoader.getEnv(OPENROUTER_KEY); + } +} diff --git a/opendaimon-starter-consumer-example/src/test/java/io/github/ngirchev/opendaimon/example/StarterConsumerApplicationContextIT.java b/opendaimon-starter-consumer-example/src/test/java/io/github/ngirchev/opendaimon/example/StarterConsumerApplicationContextIT.java new file mode 100644 index 00000000..f030de27 --- /dev/null +++ b/opendaimon-starter-consumer-example/src/test/java/io/github/ngirchev/opendaimon/example/StarterConsumerApplicationContextIT.java @@ -0,0 +1,46 @@ +package io.github.ngirchev.opendaimon.example; + +import static org.assertj.core.api.Assertions.assertThat; + +import io.github.ngirchev.opendaimon.common.meter.OpenDaimonMeterRegistry; +import io.github.ngirchev.opendaimon.rest.controller.SessionController; +import io.micrometer.core.instrument.MeterRegistry; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.PostgreSQLContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +@Testcontainers +@SpringBootTest( + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, + properties = "open-daimon.ai.spring-ai.mock=true") +class StarterConsumerApplicationContextIT { + + @Container + static final PostgreSQLContainer postgres = new PostgreSQLContainer<>("postgres:16-alpine"); + + @Autowired + private ApplicationContext applicationContext; + + @DynamicPropertySource + static void registerProperties(DynamicPropertyRegistry registry) { + registry.add("spring.datasource.url", postgres::getJdbcUrl); + registry.add("spring.datasource.username", postgres::getUsername); + registry.add("spring.datasource.password", postgres::getPassword); + } + + @Test + void applicationContextStartsWithStarterRestAndMicrometerFallback() { + assertThat(applicationContext.getBean(MeterRegistry.class)) + .isNotNull(); + assertThat(applicationContext.getBean(OpenDaimonMeterRegistry.class)) + .isNotNull(); + assertThat(applicationContext.getBean(SessionController.class)) + .isNotNull(); + } +} diff --git a/opendaimon-starter-consumer-example/src/test/java/io/github/ngirchev/opendaimon/example/StarterConsumerClasspathSmokeTest.java b/opendaimon-starter-consumer-example/src/test/java/io/github/ngirchev/opendaimon/example/StarterConsumerClasspathSmokeTest.java new file mode 100644 index 00000000..75b53907 --- /dev/null +++ b/opendaimon-starter-consumer-example/src/test/java/io/github/ngirchev/opendaimon/example/StarterConsumerClasspathSmokeTest.java @@ -0,0 +1,121 @@ +package io.github.ngirchev.opendaimon.example; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import javax.xml.XMLConstants; +import javax.xml.parsers.DocumentBuilderFactory; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.annotation.ImportCandidates; +import org.springframework.boot.env.YamlPropertySourceLoader; +import org.springframework.core.io.ClassPathResource; +import org.w3c.dom.Element; + +class StarterConsumerClasspathSmokeTest { + + @Test + void springBootDiscoversOpenDaimonAutoConfigurationsFromStarterDependency() { + var autoConfigurations = new ArrayList(); + for (String autoConfiguration : ImportCandidates.load( + AutoConfiguration.class, + StarterConsumerClasspathSmokeTest.class.getClassLoader())) { + autoConfigurations.add(autoConfiguration); + } + + assertThat(autoConfigurations) + .contains( + "io.github.ngirchev.opendaimon.common.config.CoreAutoConfig", + "io.github.ngirchev.opendaimon.bulkhead.config.BulkHeadAutoConfig", + "io.github.ngirchev.opendaimon.common.storage.config.StorageAutoConfig", + "io.github.ngirchev.opendaimon.ai.springai.config.SpringAIAutoConfig", + "io.github.ngirchev.opendaimon.ai.springai.config.RAGAutoConfig", + "io.github.ngirchev.opendaimon.ai.springai.config.AgentAutoConfig", + "io.github.ngirchev.opendaimon.rest.config.RestAutoConfig"); + } + + @Test + void exampleDeclaresStarterAndRestAsOnlyOpenDaimonDependencies() throws Exception { + assertThat(loadOpenDaimonDependencies()) + .containsExactly( + "opendaimon-spring-boot-starter", + "opendaimon-rest"); + } + + @Test + void applicationUsesStandardSpringBootEntryPoint() { + assertThat(StarterConsumerApplication.class.getAnnotation(SpringBootApplication.class)) + .isNotNull(); + } + + @Test + void starterClasspathIncludesFlywayPostgreSqlSupport() throws Exception { + assertThat(Class.forName("org.flywaydb.database.postgresql.PostgreSQLDatabaseType")) + .isNotNull(); + } + + @Test + void starterDefaultsAreAvailableFromConsumerClasspath() throws Exception { + var loader = new YamlPropertySourceLoader(); + var starterDefaults = loader + .load( + "opendaimon-defaults.yml", + new ClassPathResource("META-INF/opendaimon/opendaimon-defaults.yml")) + .getFirst(); + + assertThat(starterDefaults.getProperty("open-daimon.ai.spring-ai.enabled")) + .isEqualTo(true); + assertThat(starterDefaults.containsProperty("open-daimon.rest.enabled")) + .isFalse(); + assertThat(starterDefaults.getProperty("spring.ai.openai.base-url")) + .isEqualTo("https://openrouter.ai/api"); + assertThat(starterDefaults.getProperty("open-daimon.ai.spring-ai.models.list[0].provider-type")) + .isEqualTo("${OPENDAIMON_DEFAULT_PROVIDER:OPENAI}"); + } + + @Test + void exampleApplicationExplicitlyEnablesRestModule() throws Exception { + var loader = new YamlPropertySourceLoader(); + var application = loader + .load( + "application.yml", + new ClassPathResource("application.yml")) + .getFirst(); + + assertThat(application.getProperty("open-daimon.rest.enabled")) + .isEqualTo(true); + } + + private List loadOpenDaimonDependencies() throws Exception { + var factory = DocumentBuilderFactory.newInstance(); + factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); + + var document = factory.newDocumentBuilder() + .parse(Path.of("pom.xml").toFile()); + var dependencies = document.getElementsByTagName("dependency"); + var openDaimonDependencies = new ArrayList(); + + for (int i = 0; i < dependencies.getLength(); i++) { + Element dependency = (Element) dependencies.item(i); + String artifactId = textOf(dependency, "artifactId"); + if ("io.github.ngirchev".equals(textOf(dependency, "groupId")) + && artifactId.startsWith("opendaimon-")) { + openDaimonDependencies.add(artifactId); + } + } + + return openDaimonDependencies; + } + + private String textOf(Element element, String tagName) { + return element.getElementsByTagName(tagName) + .item(0) + .getTextContent() + .trim(); + } +} diff --git a/opendaimon-telegram/TELEGRAM_MODULE.md b/opendaimon-telegram/TELEGRAM_MODULE.md index ea39f0b9..58b625fc 100644 --- a/opendaimon-telegram/TELEGRAM_MODULE.md +++ b/opendaimon-telegram/TELEGRAM_MODULE.md @@ -559,7 +559,7 @@ Both messages are sent as replies to the original user message. such as a missing web-search query are compacted for the user while the full observation remains available to the agent loop. 5. `MAX_ITERATIONS`: model confirms the terminal output first, strips any trailing partial-answer overlay from status, then appends `⚠️ reached iteration limit`. -6. `FINAL_ANSWER` (or terminal max-iterations fallback): model confirms final answer and the view creates/edits answer message. The trailing partial-answer overlay (when a candidate was actually rendered as the status tail) is stripped from `statusHtml` so the status message does not freeze with a stale fragment (e.g. `На ос`) next to the freshly delivered answer. In `HIDE_REASONING`, a trailing reasoning overlay is also removed on confirmation; in `SHOW_ALL`, reasoning overlays are preserved. If the overlay was the only status content, it is replaced with a `✅` marker because Telegram rejects empty edits. +6. `FINAL_ANSWER` (or terminal max-iterations fallback): model confirms final answer and the view creates/edits answer message. The trailing partial-answer overlay (when a candidate was actually rendered as the status tail) is stripped from `statusHtml` so the status message does not freeze with a stale fragment (e.g. `На ос`) next to the freshly delivered answer. In `HIDE_REASONING`, a trailing reasoning overlay is also removed on confirmation; in `SHOW_ALL`, reasoning overlays are preserved. If the overlay was the only status content, it is replaced with `✅ Done` because Telegram rejects empty edits and renders lone emoji as oversized messages. ### Thinking modes diff --git a/opendaimon-telegram/pom.xml b/opendaimon-telegram/pom.xml index 10a7b105..ded6ca3f 100644 --- a/opendaimon-telegram/pom.xml +++ b/opendaimon-telegram/pom.xml @@ -208,6 +208,11 @@ junit-jupiter-api test + + org.junit.jupiter + junit-jupiter-engine + test + com.tngtech.archunit archunit @@ -255,6 +260,9 @@ maven-dependency-plugin + + org.junit.jupiter:junit-jupiter-engine com.tngtech.archunit:archunit-junit5-engine diff --git a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamModel.java b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamModel.java index 78897cc2..52eaadfa 100644 --- a/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamModel.java +++ b/opendaimon-telegram/src/main/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamModel.java @@ -20,6 +20,7 @@ public final class TelegramAgentStreamModel { public static final String STATUS_THINKING_LINE = "💭 Thinking..."; public static final String STATUS_MAX_ITER_LINE = "⚠️ reached iteration limit"; + public static final String STATUS_DONE_LINE = "✅ Done"; private static final int CANDIDATE_TAIL_LIMIT = 400; private static final String MISSING_TOOL_ARGUMENT = "missing"; @@ -232,10 +233,10 @@ private void clearTrailingStatusOverlay() { if (lastBoundary >= 0) { statusHtml.setLength(lastBoundary); } else { - // Overlay was the only content; Telegram rejects empty edits, so leave a - // minimal completion marker. + // Overlay was the only content; Telegram rejects empty edits, so leave + // text next to the emoji to avoid Telegram's oversized single-emoji render. statusHtml.setLength(0); - statusHtml.append("✅"); + statusHtml.append(STATUS_DONE_LINE); } statusDirty = true; } diff --git a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamModelTest.java b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamModelTest.java index f0888a46..019518a4 100644 --- a/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamModelTest.java +++ b/opendaimon-telegram/src/test/java/io/github/ngirchev/opendaimon/telegram/service/TelegramAgentStreamModelTest.java @@ -113,11 +113,12 @@ void shouldNotClearStatusWhenPostToolPartialWasNeverRenderedAsOverlay() { } @Test - @DisplayName("should leave completion marker when status was entirely overlay") - void shouldLeaveCompletionMarkerWhenStatusWasEntirelyOverlay() { + @DisplayName("should leave textual completion marker when status was entirely overlay") + void shouldLeaveTextualCompletionMarkerWhenStatusWasEntirelyOverlay() { // First-iteration straight-to-answer: partial chunk overwrites the initial // "💭 Thinking..." line, then FINAL arrives. Stripping leaves an empty status — - // Telegram rejects empty edits, so the model substitutes a "✅" marker. + // Telegram rejects empty edits, so the model substitutes a textual marker + // instead of a lone emoji, which Telegram renders oversized. TelegramAgentStreamModel model = new TelegramAgentStreamModel(false, false); model.apply(AgentStreamEvent.partialAnswer("Quick", 0)); @@ -127,7 +128,7 @@ void shouldLeaveCompletionMarkerWhenStatusWasEntirelyOverlay() { assertThat(model.statusHtml()) .doesNotContain("Quick") - .isEqualTo("✅"); + .isEqualTo(TelegramAgentStreamModel.STATUS_DONE_LINE); } @Test diff --git a/pom.xml b/pom.xml index 905f65a0..c2e33e61 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,7 @@ opendaimon-spring-ai opendaimon-common + opendaimon-spring-boot-starter opendaimon-ui opendaimon-rest opendaimon-telegram