Skip to content

Extend it

Kind Interface Built-ins (registry name)
store MemoryStore: insert, update, get, delete, query (+ optional vector_search) memory, sqlite, pgvector, qdrant
embedder Embedder: embed(texts) hashing (offline), ollama (local model), openai, azure_openai, function, agno
extractor Extractor: extract(messages, existing) rules (offline), llm, none
ranker Ranker: rank(query, query_embedding, records, limit=, at=) hybrid
processor Processor: process(candidate) returns the candidate or None to drop it. A plain function works too. drop_secrets (default), redact_pii, min_importance
summarizer Summarizer: summarize(messages, previous) extractive, llm
adapter Adapter: matches(target), attach(target, memory, **options), optional detach(target) agno, method, callable
intelligence manage(memory, messages, ...) - or replace one part: a router route(memory, turn), a planner plan(memory, query, ...), a scheduler after_turn(memory, report, ...) heuristic, llm
from kioko import Adapter, Embedder, MemoryLayer, MemoryMiddleware, register

@register("embedder", "minilm")
class MiniLM(Embedder):
    def __init__(self):
        from sentence_transformers import SentenceTransformer
        self.model = SentenceTransformer("all-MiniLM-L6-v2")
    def embed(self, texts):
        return self.model.encode(list(texts)).tolist()

@register("adapter", "my-framework")              # tried before the built-in adapters
class MyFrameworkAdapter(Adapter):
    def matches(self, target):
        return type(target).__module__.startswith("my_framework")
    def attach(self, target, memory, **options):
        hooks = MemoryMiddleware(memory, **options)
        target.before_turn(lambda t: t.add_context(str(hooks.before(t.text, user_id=t.user))))
        target.after_turn(lambda t: hooks.after(t.text, t.reply, user_id=t.user))
        return target

memory = MemoryLayer.from_config({          # or a path to a JSON file
    "store": {"type": "sqlite", "path": "memory.db"},
    "embedder": "minilm",                     # or {"type": "azure_openai", "deployment": "text-embedding-3-small"}
    "extractor": {"type": "llm", "llm": {"$import": "my_app.llm:complete"}},
    "processors": ["drop_secrets", "redact_pii"],
    "dedup_threshold": 0.92,
})

Ship components in their own package so pip install is all it takes. kioko components lists everything that's available:

[project.entry-points."kioko.embedders"]
minilm = "my_plugin.embedders:MiniLM"

[project.entry-points."kioko.adapters"]
my-framework = "my_plugin.adapter:MyFrameworkAdapter"

A custom store only needs five methods. See examples/04_custom_components.py for a JSON-file store in about 30 lines, and stores for the reusable contract tests. For a vector database (Azure AI Search, Elasticsearch, Milvus ...), implement vector_search, as the pgvector and Qdrant stores do. The extraction rules can be extended without a new extractor: RuleBasedExtractor(extra_rules=[Rule("ticket", r"^my ticket is (?P<id>[A-Z]+-\d+)$", template="User's open ticket is {id}", key="work.ticket", flags=0)]).