Commit Graph

11 Commits

Author SHA1 Message Date
subochev 2d6cf89c52 remove deprecated EventStore and MessageStore implementations, along with related in-memory and SQLite code
ci / JVM build + tests (push) Failing after 59s
2026-09-21 02:57:45 +03:00
subochev aef5083801 refactor: migrate EventStore and MessageStore to :outbox-api and :journal-api
ci / JVM build + tests (push) Failing after 1m9s
- Replaced usages of `:message-store-api` and `:working-memory-api` with `:journal-api`, `:outbox-api`, and `:context-api`.
- Deprecated legacy `EventStore` and `MessageStore` interfaces, added `typealias` for backward compatibility.
- Updated imports across all modules with references to `:journal-api` and `:outbox-api`.
- Introduced `journalRoutes` and `outboxRoutes` in `:server` for audit log and live event stream endpoints.
- Adjusted `Agent` to expose read-only `journal` and `outbox` stores for improved modularity and clarity.
- Removed legacy Event and AgentEvent definitions from `:proto`, migrated to `:outbox-api`.
- Storage-related modules have been updated to support the new APIs consistently.
2026-09-21 02:38:40 +03:00
subochev acc7237e51 Коммит заменяет SQLDelight на ksqlite и добавляет journal/context/outbox
ci / JVM build + tests (push) Failing after 1m24s
2026-09-21 01:12:31 +03:00
subochev d74af621d8 refactor(storage): drop StorageBundle + legacy EventStore, add HttpEventStore
ci / JVM build + tests (push) Successful in 6m13s
- Remove legacy pw.binom.agentik.messageStore.events.EventStore (EventRecord,
  EventType) and all three impls (in-memory, sqlite, ksqlite) + tests + .sq
- Drop :storage-bundle module entirely; ChatAgent / ChatConversation /
  ConversationLoop / DebugRoutes now take stores individually
  (conversationStore, messageStore, workingMemoryStore, reflectionStore,
  eventStore) instead of StorageBundle
- Delete server endpoints /events/replay and /conversations/{id}/events/replay;
  Route.agentikAgent no longer takes eventStore param
- Add :client/HttpEventStore implementing :event-store/EventStore over HTTP:
  events() -> GET /events/all, agentEvents() -> GET /events,
  conversationEvents(convId) -> GET /conversations/{id}/events;
  exposed via AgentClient.eventStore
- :event-store: add macosX64/macosArm64/linuxArm64 targets to match :client KMP
- :working-memory-api: drop api dep on :message-store-api (no longer needed)
- :storage-{inmemory,sqlite,ksqlite}: drop deps on :storage-bundle
2026-09-20 18:06:46 +03:00
subochev a05e260457 refactor(event-store): default impls for conversationEvents/agentEvents
ci / JVM build + tests (push) Failing after 1m24s
Методы conversationEvents() и agentEvents() теперь default в интерфейсе:
реализуют фильтрацию через [events] + filterIsInstance.

Зачем:
  - Минимальный контракт для impl — достаточно реализовать только events().
  - InMemoryEventStore и любой новый backend получают работающие
    specialized views автоматически, без копипасты filterIsInstance.
  - Persistent impl'ы (SQL/ksqlite) могут override'нуть для эффективности
    (WHERE conversation_id = ? — не тянуть все events в память), но
    контракт корректен и без override.

Семантика идентична:
  - conversationEvents(after, null)   = events().filterIsInstance<Conversation>()
  - conversationEvents(after, "c-1") = events()...filter { it.conversationId == "c-1" }
  - agentEvents(after)               = events().filterIsInstance<Agent>()

Imports добавлены: kotlinx.coroutines.flow.filter, filterIsInstance.
2026-09-20 15:56:59 +03:00
subochev 7e66baf9e3 feat(event-store): add conversationEvents and agentEvents filters
ci / JVM build + tests (push) Has been cancelled
Расширяет EventStore тремя вариантами подписки (вместо одного events()):

  - events(after)               → Flow<CommonEvent>
      весь поток (микс Agent + Conversation)

  - conversationEvents(after, conversationId?)
      → Flow<CommonEvent.Conversation>
      опциональный фильтр по conversationId (null = все диалоги)

  - agentEvents(after)
      → Flow<CommonEvent.Agent>
      только lifecycle (Created/Deleted/Renamed)

Типизированные subtype'ы вместо Flow<CommonEvent> + .filterIsInstance:
  - compile-time safety на клиенте (нет cast'ов в CommonEvent.Conversation)
  - persistent impl'ы могут делать WHERE conversation_id = ? на уровне БД

Соответствует HTTP-маршрутам в :server:
  - GET /events/all                       ↔ events(after)
  - GET /conversations/{id}/events         ↔ conversationEvents(after, id)
  - GET /events (только agent lifecycle)   ↔ agentEvents(after)

README обновлён — таблица caller→method показывает маппинг.

Совместимость: signals не сломаны (добавление, не изменение).
2026-09-20 15:55:14 +03:00
subochev 1134e32ea2 docs(event-store): README explaining module purpose and contract
ci / JVM build + tests (push) Failing after 1m16s
Документирует:
  - Три принципа дизайна (TTL внутри, catchup+live в одном Flow,
    read-only контракт для observer'ов)
  - Архитектуру двухуровневого хранилища событий со схемой
  - Reconnect pattern с gap detection
  - API EventStore + MutableEventStore (когда какой использовать)
  - Таблица: какой caller принимает какой интерфейс
  - Текущее состояние: interfaces готовы, implementations в работе
  - Зависимости (минимальные: :proto + kotlinx-coroutines)

В том же стиле что и :agent-toolsets/README.md.
2026-09-20 15:51:21 +03:00
subochev e2f0e434d1 refactor(event-store): split into EventStore (read-only) + MutableEventStore
ci / JVM build + tests (push) Failing after 1m49s
Разделяет интерфейс на read-only (EventStore) и write (MutableEventStore).

EventStore (read-only, для consumer'ов):
  - events(after: Instant?): Flow<CommonEvent>
  - earliestEventDate(): Instant
  - close()

MutableEventStore : EventStore (для producer'ов):
  - + append(event: CommonEvent)
  - suspend, не идемпотентный, может быть silently evicted

Зачем:
  - Consumer'ы (server SSE, admin dashboard, parent agents) принимают
    EventStore — compile-time гарантия что они не могут писать в store.
  - Producer'ы (ChatAgent, sub-agents, A2A-bridge) принимают MutableEventStore.
  - Тесты могут использовать EventStore без опасности случайной модификации.

Миграция:
  - :event-store пока без implementations, поэтому ничего не сломалось.
  - Когда добавим InMemoryEventStore — он будет реализовывать оба
    (MutableEventStore = EventStore + append). Подписки получают только
    read-only projection через приведение типа.

Также: импорт обновлён AllEvent → CommonEvent (по rename в :proto).
2026-09-20 15:46:59 +03:00
subochev 1f85cde1b8 feat(event-store): store and emit AllEvent directly
ci / JVM build + tests (push) Failing after 1m17s
Заменяет generic Event envelope (id, date, payload) на типизированный AllEvent
из :proto. EventStore теперь:

  - append(event: AllEvent)
  - events(after: Instant?): Flow<AllEvent>
  - earliestEventDate(): Instant

Изменения:
  - :event-store теперь зависит от :proto (api dependency).
  - Event.kt удалён — AllEvent уже живёт в :proto и несёт date, conversationId,
    typed envelope (Agent или Conversation variant).
  - Generic opaque payload выкинут — typesafety до самого storage.
  - append НЕ идемпотентен (AllEvent не имеет уникального id, два retry
    дадут дубликат). Документировано: для exactly-once использовать catchup
    через :message-store-api (там есть монотонный id).

В KDoc примере reconnect убран лишний null-check у earliestEventDate
(теперь всегда non-null).

Миграция (когда будем интегрировать):
  Producer в :standalone перестаёт делать двойную работу
  (MutableSharedFlow + persistAgentEvent). Вместо этого — один
  eventStore.append(allEvent). Caller'ы SSE будут делать
  store.events(after) → Flow<AllEvent>, без ручной конвертации.

Build green на JVM.
2026-09-20 15:44:17 +03:00
subochev 8bb24dab3c refactor(event-store): earliestEventDate returns non-nullable Instant
ci / JVM build + tests (push) Failing after 1m50s
Раньше возвращал Instant? — null для пустого буфера. Клиенту приходилось
проверять if (earliest != null && ...) — легко ошибиться.

Теперь всегда Instant. Если буфер пуст, возвращает Clock.System.now()
на момент вызова. Это убирает nullable + сохраняет семантически корректное
поведение:

  - Клиент может безопасно сделать store.events(earliest) → получит только
    live event'ы, без ложного catchup.
  - Если бы возвращали null/DISTANT_PAST/null-check, клиент мог бы ошибочно
    подписаться на несуществующий catchup-диапазон.

Edge case (в KDoc): клиент, подключившийся ДО первого event'а, получает
earliest ≈ now. Его lastSeen < earliest → адаптируется в первом poll'е.

Изменение breaking — но :event-store ещё не имеет implementations и
никакие consumer'ы не используют этот метод.
2026-09-20 15:41:30 +03:00
subochev 7358175499 feat(event-store): new :event-store module with interfaces only
ci / JVM build + tests (push) Failing after 1m54s
Выделяет bounded-tail event log в отдельный KMP-модуль. Это **новый
контракт** (не замена :message-store-api/events/EventStore — тот пока жив).

**Двухуровневое хранилище событий**:
  1. :event-store (этот PR) — короткий bounded tail, авто-TTL.
     Для live SSE и recent replay (catchup после короткого disconnect).
  2. :message-store-api (MessageStore) — полный audit log, никогда не
     эвиктится. Source of truth для длинного disconnect / audit query.

**API**:
  - append(Event) — put, идемпотентный по id
  - events(after: Instant?): Flow<Event> — catchup + live в одном Flow
  - earliestEventDate(): Instant? — для gap detection у клиента

**Чего НЕТ в API** (by design):
  - delete/prune методов — TTL/cap eviction полностью на стороне impl.
    Caller'ы не должны забыть вызвать cleanup (single source of truth).
  - conversationId / type в Event — opaque payload, тип envelope'а
    решает producer.

Пока interfaces only — implementations (InMemoryEventStore, persistent)
появятся в следующих коммитах. Никаких изменений в существующем
EventStore в :message-store-api, чтобы не ломать зависимости.

KMP targets: jvm + linuxX64 + mingwX64 (Apple auto-disabled на Linux).

Modules:
  + :event-store — новый, commonMain only, ~150 строк
2026-09-20 15:38:05 +03:00