Koog 1.3 idioms, gotchas, and scaffolding skills for Kotlin agents on the JVM
72
91%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
This skill is an action router — pick the step that matches the user's intent and execute only that step. Do not run other steps; do not parallelize.
Available actions:
AIAgentStorage + createStorageKey)HistoryCompressionStrategy)LongTermMemory feature)storage on AIAgentContext is the typed key-value store. Keys are created once at file scope; values are read/written inside node bodies:
import ai.koog.agents.core.agent.entity.AIAgentStorage
import ai.koog.agents.core.agent.entity.createStorageKey
val unfinishedNodesKey = createStorageKey<MutableList<String>>("unfinishedNodes")
val currentNodeKey = createStorageKey<String>("currentNode")
suspend fun rememberNode(storage: AIAgentStorage, ref: String): String? {
storage.set(currentNodeKey, ref)
return storage.get(currentNodeKey)
}Constraints (1.0):
@Serializable — storage is checkpointed (KG-673). Non-serializable types (thread-locals, open file descriptors, raw clients) break checkpointing silentlyAIAgentStorageKey equality is name-based — two keys with the same string name collide regardless of file locationAIAgentStorage() constructor was removed; use AIAgentStorage(serializer) when constructing one manuallytoMap() was removed — iterate via the key set if you need to inspectstateManager (also on AIAgentContext) is for agent-lifecycle state, not application data. Don't pile arbitrary data into stateManager.
Finish here.
Long agentic runs blow the context window. Compression rules:
Default to HistoryCompressionStrategy.WholeHistory (a single TL;DR) unless the user explicitly asks for last-N, time-window, chunked, or fact-extraction shape. Write the modified node body to disk with an explicit Path: label (same convention as scaffold-agent):
Path: src/main/kotlin/com/example/Strategy.kt — boundary node with the replaceHistoryWithTLDR call (or whichever file defines the strategy / boundary node)Create the file if it doesn't exist. Do not respond with prose only.
// inside the boundary node body (between exploration and drafting, for example)
llm.writeSession {
replaceHistoryWithTLDR() // WholeHistory is the default; pass strategy = HistoryCompressionStrategy.X only when overriding
}Other strategy variants (use only when the user names them — pass via replaceHistoryWithTLDR(strategy = HistoryCompressionStrategy.X) and add import ai.koog.agents.core.dsl.extension.HistoryCompressionStrategy):
HistoryCompressionStrategy.NoCompression — keep everythingHistoryCompressionStrategy.WholeHistoryMultipleSystemMessages — multi-message summaryHistoryCompressionStrategy.FromLastNMessages(n) — keep the last N, drop the restHistoryCompressionStrategy.FromTimestamp(instant) — keep messages after timestampHistoryCompressionStrategy.Chunked(chunkSize) — chunk-by-chunk summarizationHistoryCompressionStrategy.FactRetrieval(concepts) — extract structured facts about named conceptsFactRetrieval was extracted from the removed AgentMemory feature in 1.0 — it's now usable standalone in agents-core, no memory feature required.
Finish here.
LongTermMemory)AgentMemory was removed in 1.0. Use LongTermMemory for memory that persists across agent runs.
Add the dependency:
implementation("ai.koog:agents-features-longterm-memory:1.3.0-beta")
// for Bedrock AgentCore backend (one option):
implementation("ai.koog:agents-features-longterm-memory-aws:1.3.0-beta")Install the feature inside AIAgent(...)'s trailing lambda. Supply a search storage
for retrieval and a write storage for ingestion; one backend may implement both.
import ai.koog.agents.core.agent.AIAgent
import ai.koog.agents.longtermmemory.feature.LongTermMemory
import ai.koog.agents.longtermmemory.feature.FailurePolicy
import ai.koog.prompt.executor.model.PromptExecutor
import ai.koog.prompt.executor.clients.openai.OpenAIModels
import ai.koog.rag.base.TextDocument
import ai.koog.rag.base.storage.SearchStorage
import ai.koog.rag.base.storage.WriteStorage
import ai.koog.rag.base.storage.search.SearchRequest
fun memoryAgent(
executor: PromptExecutor,
searchStorage: SearchStorage<TextDocument, SearchRequest>,
writeStorage: WriteStorage<TextDocument>,
) = AIAgent(
promptExecutor = executor,
llmModel = OpenAIModels.Chat.GPT4o,
systemPrompt = "Retrieve relevant facts and remember this conversation.",
) {
install(LongTermMemory) {
retrieval {
storage = searchStorage
failurePolicy = FailurePolicy.FAIL_FAST
}
ingestion {
storage = writeStorage
failurePolicy = FailurePolicy.LOG_AND_CONTINUE
}
}
}Set searchQueryProvider inside retrieval {} and documentExtractor inside
ingestion {} when overriding their defaults. FAIL_FAST throws on a backend
failure; LOG_AND_CONTINUE logs it and continues. Omit either block to disable that
capability. An empty feature configuration enables neither capability.
1.0 renames in LongTermMemory (apply when migrating):
QueryExtractor → SearchQueryProviderExtractionStrategy → DocumentExtractorIngestionTiming was removed — strategies now manage ingestion timing internallyIf the user's need is "agent should remember things within one run but not across runs," they don't need LongTermMemory — Step 1 (storage) covers it.
Finish here.
.tessl-plugin
skills
add-observability
add-persistence
references
add-rag
add-structured-output
add-token-budgeting
add-tool
cache-llm-calls
define-prompt
domain-model-subtask-pipeline
references
enable-prompt-caching
handle-agent-events
manage-state
migrate-from-0-x
model-planner-subtasks
persist-chat-history
query-sql-from-agent
scaffold-agent
snapshot-and-restore
references
test-koog-agents
trace-agent-internals
use-agent-skills
references
use-attachments
use-cli-agents
use-functional-agent
use-llm-node-variants
use-planner
wire-a2a
wire-acp-server
wire-ktor-server
wire-mcp-server
wire-spring-boot