Character chat engine core — Protocol-based storage, dependency-injectable ChatEngine
Project description
kokoro-chat
Character chat engine core — extracted from roleplay-chat.
Protocol-based storage interfaces + dependency-injectable ChatEngine. No database or web framework dependencies.
Features
- ChatEngine — full LLM conversation loop with tool calling (attitude, memory, memo, search)
- Protocol-based storage — 9
@runtime_checkableProtocol interfaces; inject any DB backend - Character system — YAML V2 character cards with lorebook, attitude levels, few-shot examples
- Attitude system — affection/trust tracking (0-100) with time decay, event-triggered modifiers, 5 relationship levels
- Memory — semantic search + rolling summary + structured memo with room/private visibility
- Lorebook — keyword-triggered context injection with token budget and priority sorting
- Prompt assembly — static (slim) and full paths with progressive degradation on budget overflow
- Streaming — async generator yielding
text_delta/message_completeevents - Multi-provider LLM — Anthropic, OpenAI, MiniMax via motosan-ai
Architecture
kokoro_chat/
├── character/ ← Character model + YAML V2 loader
├── lorebook/ ← Lorebook engine (keyword trigger → context injection)
├── attitude/ ← AttitudeState + 5 behavior levels (stranger → married)
├── memory/ ← Memo stale-filtering logic
├── prompt/
│ ├── assembler.py ← System prompt assembly (static + full paths)
│ ├── sections.py ← Shared section builders (character, traits, speech...)
│ ├── budget.py ← Token budget constants + estimator
│ └── formatter.py ← Conversation history formatting
├── providers/ ← Context providers (attitude, persona, recent_chat)
├── tools/ ← LLM tools (update_attitude, save_memory, upsert_memo, search_memories)
├── storage/ ← 9 Protocol interfaces (DB-agnostic)
├── engine/
│ ├── chat.py ← ChatEngine (orchestration)
│ ├── llm.py ← LLM client factory + bridges
│ ├── attitude_manager.py ← AttitudeManager
│ ├── message_manager.py ← MessageManager
│ ├── summarizer.py ← Summarizer
│ └── background.py ← Background task prompts + parsers
└── config.py ← ChatConfig dataclass
Installation
pip install kokoro-chat
Or from source:
pip install -e ".[dev]"
Quick Start
from kokoro_chat import Character, ChatConfig, ChatEngine
# 1. Build a Character (from DB model or manually)
character = Character(
id="xing_lang",
name="星浪",
description="一個活潑開朗的女孩,喜歡音樂和冒險。",
personality_summary="外向、好奇心強、有點衝動",
likes=["音樂", "冒險", "甜食"],
default_mood="happy",
)
# 2. Configure
config = ChatConfig(
chat_provider="anthropic",
chat_model="claude-sonnet-4-5-20250929",
anthropic_api_key="sk-ant-...",
)
# 3. Inject your storage implementations (must implement the Protocols)
engine = ChatEngine(
config=config,
attitude_store=your_attitude_store, # AttitudeStore
cache=your_cache_store, # CacheStore
chat_history=your_history_store, # ChatHistoryStore
chat_writer=your_message_writer, # ChatMessageWriter
memory_store=your_memory_store, # MemoryVectorStore
memo_store=your_memo_store, # MemoStore
rolling_summary_store=your_summary_store, # RollingSummaryStore
event_store=your_event_store, # EventStore
)
# 4. Stream a conversation
async for chunk in engine.chat_stream(
user_message="你好啊",
character=character,
user_id="user-123",
chat_mode="short",
):
if chunk["type"] == "text_delta":
print(chunk["text"], end="", flush=True)
elif chunk["type"] == "message_complete":
print() # done
Storage Protocols
All storage interfaces are typing.Protocol with @runtime_checkable.
Implement any concrete backend (PostgreSQL, SQLite, in-memory dict) — as long as it matches the protocol signature.
from kokoro_chat.storage.protocol import (
AttitudeStore, # get / get_or_create / save — affection, trust, mood
ChatHistoryStore, # get_recent — recent messages
MemoryVectorStore, # search / add — semantic memory with visibility
MemoStore, # get / upsert — key-value user info
RollingSummaryStore, # get_or_create / update — compressed history
EventStore, # get_by_character — character/user events
UsageLogStore, # log — token count + cost tracking
ChatMessageWriter, # add_message — persist new messages
CacheStore, # get/set attitude, messages, rolling summary
)
See kokoro_chat/storage/protocol.py for full protocol definitions and value objects (ChatMessage, AttitudeRecord, MemorySearchResult, RollingSummaryRecord, EventRecord).
Attitude System
Characters have dynamic attitude toward each user:
affection: 0-100 (好感度)
trust: 0-100 (信任度)
mood: string (當前心情)
5 relationship levels based on affection score:
| Level | Range | Behavior |
|---|---|---|
| stranger | 0-20 | Polite, distant, formal |
| friend | 21-40 | Casual, joking, caring |
| crush | 41-60 | Shy, blushing, finding excuses to get closer |
| lover | 61-80 | Intimate, clingy, using pet names |
| married | 81-100 | Maximum intimacy, deep trust |
- Time decay — affection/trust decrease after 3+ days of inactivity (floor: affection 30, trust 20)
- Event-triggered modifiers — temporary attitude shifts with turn-based countdown
- Custom overrides — characters can define their own behavior text per level
Room Memory
Characters in the same room share non-private memories:
# save_memory tool — LLM decides visibility
save_memory(text="User is learning guitar", visibility="room") # shared in room
save_memory(text="User has a crush on NPC", visibility="private") # only this character
# search_memories — returns own + same-room memories
results = await memory_store.search(
query="music",
character_id="xing_lang",
user_id="user-123",
room_id="cafe", # includes other characters' room-visible memories
)
Character Card V2
Supports standard Character Card V2 format with Kokoro extensions:
| Extension | Purpose |
|---|---|
speech_patterns_v2 |
Mood-based speech patterns ({mood: pattern}) |
affection_overrides |
Custom behavior text per relationship level |
post_history_by_level |
Level-specific post-history instructions |
anti_patterns |
Prevent character drift ({bad, correct, why}) |
Load from YAML V2:
from kokoro_chat.character.loader import map_v2_yaml_to_db
db_kwargs = map_v2_yaml_to_db(yaml_data) # → dict for DB model creation
Load from DB model:
character = Character.from_db_model(db_char) # duck-typed, reads attributes
Dependencies
| Package | Purpose |
|---|---|
motosan-ai |
LLM client (Anthropic, OpenAI, MiniMax) |
motosan-chat |
AgentLoop, ContextProvider, Tool framework |
pyyaml |
YAML V2 character card parsing |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file kokoro_chat-0.1.2.tar.gz.
File metadata
- Download URL: kokoro_chat-0.1.2.tar.gz
- Upload date:
- Size: 93.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.6 {"installer":{"name":"uv","version":"0.10.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ece638813d2c3900fa2f52c062875314c0c0dccaec590a2da245acf37cb341d7
|
|
| MD5 |
9661f26d6f127b3f2d716d87c48113f5
|
|
| BLAKE2b-256 |
dbfd17e601e28c3509aa17e4faa09d5875da53ecdd80f3f18ccbefb0255aef60
|
File details
Details for the file kokoro_chat-0.1.2-py3-none-any.whl.
File metadata
- Download URL: kokoro_chat-0.1.2-py3-none-any.whl
- Upload date:
- Size: 53.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.6 {"installer":{"name":"uv","version":"0.10.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b8338872fc3dfa0125e368b6881bf184edf8ebd190f480c2b011569fe7dfed29
|
|
| MD5 |
58a0cc166b0e849cdf0f1ccb621e87a2
|
|
| BLAKE2b-256 |
ceffea00a9ada109470a49b9533e335f70b26c4e1344d822e2d36e4dca678859
|