Standalone refactor — modularity + correctness improvements after
STANDALONE-REVIEW findings. Touches ~30 files. Build green, 178 tests pass.
(1) Module extractions — generic components out of :standalone:
• :llm-tools (new KMP module, package pw.binom.agentik.llm.tools)
- LlmReflector, SkillMiner, LlmMemoryReviewer, LiteLlmContextCompactor
- Parsers: ReflectionParser, SkillMiningParser, ReviewDecisionParser
- Prompts: ReflectionPrompts, SkillMiningPrompts, ReviewPrompts
• :mcp-bridge (new JVM module, package pw.binom.agentik.mcp.bridge)
- McpConfig, McpRegistry, McpLiteToolAdapter
• NamedTool moved from :standalone to :agent-toolsets/commonMain
- Generic (name + LiteTool) wrapper, used by both :mcp-bridge
and :standalone's tool dispatcher
:standalone loses ~1400 lines, depends on the two new modules.
(2) Background work → event-driven (no more interval-polling):
• New :standalone/agent/BackgroundEvents.kt — internal event bus:
- ToolCallEvent.Succeeded/Failed (emitted by ToolDispatcher after invoke)
- CompactionEvent.Triggered (emitted by CompactionCoordinator pre-delete)
- ConversationLifecycleEvent.Closing (emitted by ConversationLoop.close)
• BackgroundScheduler rewritten as event subscriber:
- On Closing: final reflection + skill mining (last-chance extraction)
- On Compaction (turnsToDelete > 10): skill mining (debounced 60s)
- On ToolFailure x2 in 60s window: reflection (debounced 5min)
- Dropped: maybeScheduleReview/Reflection/SkillMining (interval-based)
- Dropped config: memoryReviewInterval, reflectionInterval, skillMiningInterval
• ToolDispatcher emits ToolCallEvent after each invoke.
• CompactionCoordinator emits CompactionEvent before workingMemory.compact().
• ConversationLoop.close() emits Closing BEFORE agentScope.cancel() so the
subscription gets to run final reflection/mining.
Net effect: typical 30-turn conversation runs ~38 LLM calls (was: 30 main +
3 review + 3 reflection + 2 mining). With event-driven, review/mining only fire
when their triggers actually make sense (compaction about to delete, or
conversation closing).
(3) AppConfig single source of truth:
• Replaces AgentikConfig + LlmConfig.fromEnv + McpConfig.fromEnv with one
AppConfig.fromEnv() that reads all ~25 env vars in a single pass.
• Sections: AgentSection, LlmSection, McpSection, MemorySection,
EmbeddingSection, ReflectionSection, SkillMiningSection, DebugSection.
• OPENAI_CONTEXT_WINDOW / AGENTIK_GOOGLE_CONTEXT_WINDOW no longer
read twice (was a bug per STANDALONE-REVIEW E3).
(4) Other fixes inherited from earlier waves:
• Hardening — size caps on user-input boundaries:
MAX_MEMORY_CONTENT_LEN=32KB, MAX_SKILL_BODY_LEN=64KB,
MAX_MCP_CONFIG_BYTES=1MB, MAX_A2A_REPLY_LEN=10MB, MAX_PORT=65535,
blank-rejection in LlmConfig.requireEnv, URL/command validation.
• Single scope — :standalone/agent/ConversationLoop has one
agentScope (was: scope + backgroundScope).
• liteConvRef race fix — capture-then-use pattern replaces !!-after-read;
close() + runTurn.finally race on LiteConv JNI handled via
AtomicReference.getAndSet.
• SkillMiner.maxTurns / LlmReflector.maxTurns exposed as public (needed
by BackgroundScheduler for prompt sizing).
• Tests: MemoryWiringTest updated for new compaction-triggered review
behavior; all parser/test imports updated for new packages.
Test results: 178/178 in :standalone, 36/36 in :agent-toolsets — all green.
:standalone — single-jar HTTP-сервер со всеми транспортами
Что это
Главный исполняемый модуль проекта — single-jar HTTP-сервер с:
- AG-UI transport на
POST /agui(SSE) +GET /health. - A2A transport на
POST /(JSON-RPC) +GET /.well-known/agent-card.json. :prototransport наPOST /agentik/*(HTTP+JSON+SSE) — наш stateful.- Embedded LLM backend:
GOOGLE(LiteRT) илиOPENAI-совместимый (vLLM, LiteLLM, OpenAI API). - SQLite persistence через
:storage-sqlite. - Memory backend:
md(файловый) илиvector(SQLite+JVector+ HTTP/SIGLIP-embeddings). - Skills из
~/.agentik/skills/*.md. - SOUL из
~/.agentik/SOUL.md. - Background подпроцессы: рефлексия, skill-mining, memory-reviewer.
Решает: даёт пользователю один JAR (10–250 МБ), который запускается
через java -jar agentik-0.1.0-all.jar, и поднимает сразу все
транспорты, которые другие системы могут хавать.
Как запустить
Требования
- JVM 21+.
- (Опционально) CUDA-устройство для
:backend=google(LiteRT). - (Опционально) LM через OpenAI-совместимый endpoint (vLLM / Ollama
/ OpenAI) для
:backend=openai.
Запуск из готового fatjar
java --enable-native-access=ALL-UNNAMED \
-jar agentik-0.1.0-all.jar
С дефолтами — встроенный SQLite, OpenAI-compatible backend на
http://localhost:8001/v1, порт 8080.
Запуск через Gradle (dev)
./gradlew :standalone:run
pull-model subcommand (для LiteRT)
# Сначала скачать модель под LiteRT-Gemma-4-E2B
AGENTIK_LLM_BACKEND=google \
AGENTIK_GOOGLE_MODEL_PATH=/root/gemma-4-E2B-it.litertlm \
java --enable-native-access=ALL-UNNAMED \
-jar agentik-0.1.0-all.jar pull-model
Скачивает https://static.binom.pw/models/gemma-4-E2B-it.litertlm
(2.5 ГБ, с Range-resume). Поддерживает override через
AGENTIK_GOOGLE_MODEL_URL и verify через
AGENTIK_GOOGLE_MODEL_SHA256_URL.
Переменные среды
Полный список — общий для всего :standalone-процесса:
| Env | Default | Что делает |
|---|---|---|
AGENTIK_PORT |
8080 |
Порт HTTP-сервера |
AGENTIK_DB_PATH |
./agentik.db |
Путь к SQLite |
AGENTIK_AGENT_ID |
agentik |
ID агента (для multi-instance) |
AGENTIK_LLM_BACKEND |
openai |
openai или google |
AGENTIK_LLM_MODEL |
(выбирается по backend) | Имя модели |
AGENTIK_LLM_API_URL |
http://localhost:8001/v1 |
Endpoint для OpenAI-compatible |
AGENTIK_LLM_API_KEY |
no-key-needed |
Auth header |
AGENTIK_LLM_CONTEXT_TOKENS |
115000 |
Сколько токенов остаётся модели |
AGENTIK_GOOGLE_MODEL_PATH |
/root/gemma-4-E2B-it.litertlm |
Путь к .litertlm файлу |
AGENTIK_GOOGLE_MODEL_URL |
https://static.binom.pw/models/gemma-4-E2B-it.litertlm |
Откуда скачивать |
AGENTIK_GOOGLE_MODEL_SHA256_URL |
— | Если задан — verify по SHA-256 |
AGENTIK_AUTO_DOWNLOAD_MODEL |
0 |
1 = скачать модель если её нет |
AGENTIK_MEMORY_BACKEND |
vector |
md, vector или off |
AGENTIK_EMBEDDING_BACKEND |
http |
http или siglip (только для vector) |
AGENTIK_EMBEDDING_API_URL |
http://localhost:8001/v1 |
Endpoint для эмбеддингов |
AGENTIK_EMBEDDING_MODEL |
text-embedding-3-small |
Имя embedding-модели |
AGENTIK_SOUL_PATH |
~/.agentik/SOUL.md |
Путь к SOUL.md |
AGENTIK_SKILLS_DIR |
~/.agentik/skills/ |
Каталог SKILL.md |
AGENTIK_MEMORY_DIR |
~/.agentik/memory/ |
Каталог для md-памяти |
AGENTIK_TOOLSETS_DEFAULT |
memory,skills,files,web |
Включённые тулы |
AGENTIK_DEBUG |
0 |
1 = verbose logging |
Значения читаются через AgentikConfig.fromEnv() в :standalone/.../Main.kt.
Эндпоинты
| Метод | Путь | Transport | Описание |
|---|---|---|---|
GET |
/health |
любой | health-check ({"ok":true}) |
POST |
/agui |
AG-UI | Стриминг run (SSE) |
POST |
/ |
A2A | JSON-RPC message/send, tasks/get, tasks/cancel |
GET |
/.well-known/agent-card.json |
A2A | Discovery |
POST |
/agentik/conversations |
:proto | Создать диалог |
GET |
/agentik/conversations |
:proto | Список диалогов |
GET |
/agentik/conversations/:id |
:proto | Snapshot |
GET |
/agentik/conversations/:id/messages |
:proto | История |
POST |
/agentik/conversations/:id/send |
:proto | Send (SSE) |
GET |
/agentik/conversations/:id/events |
:proto | Live-events (SSE) |
POST |
/agentik/conversations/:id/interrupt |
:proto | Прервать |
POST |
/agentik/conversations/:id/rename |
:proto | Переименовать |
DELETE |
/agentik/conversations/:id |
:proto | Удалить |
Тесты
./gradlew :standalone:jvmTest # unit-тесты
./gradlew :standalone:integrationTest # integration (Testcontainers)
./gradlew :standalone:shadowJar # → build/libs/agentik-0.1.0-all.jar
Известные ограничения
- vLLM не поддерживает cancel-inference (
interrupt()только закрывает client SSE-socket; бэкенд всё равно генерирует до конца). - A2A JSON discriminator —
"kind"(text/file/data), а не"type". См.A2aJsonв:standalone. - SSE в не-TTY ssh закрывается на default Ktor timeout.
Текущий статус
Production-ready. Все KMP-модули проекта интегрированы. Полный
manual-test checklist смотрите в MANUAL-TESTS.md
или MANUAL-TESTS.md в корне.
Где скачать
- Source:
git clone https://git.binom.pw/subochev/agentik - Fatjar: Gitea CI artifacts (через
.gitea/workflows/release.ymlна tagv*) или собирается через./gradlew :standalone:shadowJar.
Версии
Все gradle/libs.versions.toml. Поднять версию → release через
git tag v0.2.0 && git push --tags → CI собирает все KMP-таргеты
публикует артефакты.