Добавлена собственная авторизация по токену. Это ОТДЕЛЬНАЯ подсистема:
библиотека A2A (pw.binom.a2a) имеет свой независимый token, общих типов
и общей логики не вводится.
Поведение по умолчанию не меняется: token = null -> авторизация выключена,
сервер открыт (обратная совместимость), CLI/TUI не затронуты.
Сервер (:server):
- новый route-scoped плагин BearerTokenPlugin (BearerTokenConfig);
- agentikAgent(agent, path, token) ставит плагин на всё поддерево /agentik,
когда token != null; иначе плагин не устанавливается;
- при несовпадении заголовка Authorization: Bearer <token> -> 401 Unauthorized;
- /health всегда открыт (liveness для балансировщика).
Клиент (:client):
- defaultAgentikHttpClient(token) навешивает Authorization: Bearer <token>
через DefaultRequest на весь HttpClient -> накрывает все 10 вызовов и оба SSE;
- AgentikAgent(id, baseUrl, token, httpClient) — token необязательный,
9 существующих мест создания агента не тронуты.
Standalone:
- AgentSection.authToken (env AGENTIK_TOKEN) -> /agentik;
- AgentSection.a2aToken (env AGENTIK_A2A_TOKEN) -> /a2a;
- два независимых значения, связи между ними нет.
Тесты: BearerTokenTest (5), BearerHeaderTest (3) — 401 без токена и с чужим,
200 с верным, /health открыт, null -> открыто. Мутационная проверка пройдена.
- build.gradle.kts (root): настроен maven-publish для всех сабпроектов;
репо 'caffeine' (Nexus) с setAllowInsecureProtocol=true, POM-метаданные
(Apache-2.0, subochev as developer, scm). Version берётся из -Pversion=<tag>
с fallback 0.1.0.
- gradle.properties: дефолтная version=0.1.0 для локальных билдов.
- .gitea/workflows/release.yml: триггер на release.published; две job'ы —
publish-libraries (subochev/devops/publish action с BINOM_REPO_* env-vars)
и build-standalone (собирает :standalone shadowJar, прикрепляет
standalone-<version>-all.jar и sources.jar к release assets через
softprops/action-gh-release + GITEA_TOKEN).
- В пяти KMP-модулях (skills, storage-core, agent-toolsets, server, client)
добавлен api(libs.kotlinx.serialization.core) — раньше commonMain
компилировался только на JVM, и эта зависимость была пропущена; теперь
commonMain корректно публикуется как Gradle Module Metadata.
Локальная проверка:
./gradlew publishToMavenLocal — все 11 модулей × 9-10 таргетов
./gradlew jvmTest — все тесты зелёные
./gradlew :standalone:shadowJar — 240MB fatjar, Main-Class загружается
Punkt 6 of NATIVE-COMPATIBILITY.md. Mirrors :proto's target set:
jvm + macosX64 + macosArm64 + iosX64 + iosArm64 + iosSimulatorArm64
+ linuxX64 + linuxArm64 + mingwX64.
All 9 targets compile via './gradlew :server:assemble'.
No blockers: the only deps (ktor-server-core, ktor-server-content-
negotiation, ktor-serialization-kotlinx-json, kotlinx-coroutines-core,
kotlinx-serialization-json) ship native variants for every target.
kotlin.time.Instant was already in use (not the deprecated
kotlinx.datetime.Instant), so no proto-side work needed.
Only API change vs the JVM version: respondTextWriter (JVM-only) ->
respondBytesWriter + writeStringUtf8 (KMP, ByteWriteChannel API).
SSE behaviour is identical ('data: <json>\n\n' chunks flushed as
they arrive).
Verification: :standalone:jvmTest 44/44 green after the migration
(ChatAgent 15, LlmConfig 6, McpConfig 8, McpRegistry 4, Persistence 11).
No call-site changes needed; :standalone picks up the new :server
jvm artifact automatically.
Major additions:
* :proto (KMP submodule) — in-house stateful protocol replacing AG-UI.
Agent owns conversation transcript; Conversation.events(after) is a live,
replay-free stream; backfill via Conversation.getMessages(after, offset, limit).
Each Event carries an Instant date for client-side resume tracking.
Sealed hierarchies (Content/Message/Event/AgentEvent) annotated @Serializable
with snake_case @SerialName JSON discriminators so the wire format is
decoupled from Kotlin class names.
* :server (JVM, Ktor 3.1.3) — REST+SSE facade for Agent.
Public entry: Route.agentikAgent(agent, path = "/agentik").
Endpoints: create/list/get/patch/delete conversations, POST messages (202),
POST interrupt, GET messages, GET conversation events (SSE),
GET agent events (SSE), GET /health. Custom Instant serializer for
kotlin.time.Instant registered contextually on agentikJson (ISO-8601,
ignoreUnknownKeys=true, explicitNulls=false).
* :client (JVM, Ktor HTTP Client + CIO) — mirror of :server returning
a pw.binom.agentik.proto.Agent backed by HTTP calls. Custom SSE parser
since ktor-client-sse is not on the 3.1.3 client classpath.
* standalone — EchoProtoAgent (in-memory Agent for :proto), EchoAgent
(existing AG-UI echo), both mounted on the same Netty embedded server
on port 8080 (/agui and /agentik); A2A stays on its own CIO engine on
8081. EchoProtoAgent smoke-tested end-to-end against :server: all 11
endpoints, including live SSE delivery of StartResponse/AppendText/End
event triplets and Agent-level Created/Deleted events.
Design notes pinned in:
* agentik/IRC-QUESTIONS.md — closed 13-item checklist for the upcoming
:irc-server transport (channel = conversation, CTCP for structural
events, draft/chathistory for backfill, ImageStore side-channel, etc).
* docs/ARCHITECTURE.md — overall layout snapshot.