Production-ready agent framework with plugin architecture, SOLID principles, and comprehensive security.
- ✅ Plugin & Play: Swap memory, retrieval, prompts without code changes
- ✅ RAG Support: Built-in retrieval systems for context-augmented agents
- ✅ Security First: Input validation, path sanitization, resource limits
- ✅ SOLID Design: Dependency injection, interface-based extensibility
- ✅ Graph Orchestration: LangGraph-style DAG execution with conditional routing
- ✅ Multi-Agent: CrewAI-style orchestration for agent teams
- ✅ Async/Sync: Seamless handling of sync and async functions
- ✅ Comprehensive Docs: Every function explains WHY and HOW to reuse
from nkit import Agent
def my_llm(prompt: str) -> str:
# Your LLM API call here
return llm_response
agent = Agent(llm=my_llm)
result = agent.run("What is the capital of France?")
print(result)from nkit import Agent
from nkit.retrieval import InMemoryRetriever
from nkit.memory import JSONFileMemory
# Setup knowledge base
retriever = InMemoryRetriever()
retriever.add_documents([
{"content": "Paris is the capital of France", "metadata": {"source": "geo.txt"}},
])
# Custom prompt service with RAG
from nkit.prompt import ReActPromptService
class RAGPromptService(ReActPromptService):
def __init__(self, retriever, **kwargs):
super().__init__(**kwargs)
self.retriever = retriever
def build_agent_prompt(self, task, tools, history, memory=None):
docs = self.retriever.retrieve(task, top_k=3)
context = "\n".join([d["content"] for d in docs])
base = super().build_agent_prompt(task, tools, history, memory)
return f"Context:\n{context}\n\n{base}"
# Create agent with plugins
agent = Agent(
llm=my_llm,
memory=JSONFileMemory("./session.json"),
prompt_service=RAGPromptService(retriever)
)
result = agent.run("What is the capital of France?")from nkit.chain import Graph, Node, State
def plan(state: State):
return {"plan": ["analyze", "summarize"]}
def execute(state: State):
plan = state.get("plan")
return f"Executed: {plan}"
g = Graph()
g.add_node(Node("plan", plan)).add_node(Node("exec", execute))
g.add_edge("plan", "exec")
final = g.run(State())
print(final.last_result)from nkit import Agent
from nkit.security import PathValidator, ToolInputValidator
# Path validation
path_val = PathValidator(allowed_dirs=["./data"])
@agent.tool("safe_read", "Read file safely")
def read_file(file_path: str) -> str:
validated = path_val.validate_path(file_path)
with open(validated, 'r') as f:
return f.read()nkit/
├── nbagents.py # Core Agent with ReAct reasoning
├── interfaces.py # Abstract interfaces (MemoryStore, PromptService, etc.)
├── memory/ # Memory backends (Memory, JSONFileMemory)
├── prompt.py # Prompt services (ReActPromptService, PromptTemplate)
├── tools/ # Tool system (Tool, ToolRegistry, BuiltinTools)
├── retrieval.py # RAG retrievers (InMemoryRetriever, JSONDocumentRetriever)
├── security.py # Input validators (PathValidator, StringValidator)
├── chain/ # Graph orchestration (Graph, Node, Edge, State)
├── agents/ # Multi-agent coordination (MultiAgentOrchestrator)
└── examples/ # Runnable demos
See ARCHITECTURE.md for comprehensive design documentation.
Agent: Orchestration onlyPromptService: Prompt constructionResponseParser: Output parsingToolRegistry: Tool management
- Extend via plugins (tools, memory, prompts)
- No core modification needed
- Swap any
MemoryStoreimplementation - Swap any
PromptServiceimplementation
- Small, focused interfaces
- Implement only what you need
Agentdepends on abstractions (protocols/ABCs)- Inject dependencies via constructor
- Input Validation: Path traversal prevention, character whitelisting
- Resource Limits: Max steps, retries, memory size, history length
- Injection Prevention: Key validation, prompt sanitization, JSON depth limits
- Least Privilege: Directory whitelisting, no shell execution by default
Example:
from nkit.security import PathValidator
validator = PathValidator(allowed_dirs=["/data"])
safe_path = validator.validate_path("/data/file.txt") # OK
validator.validate_path("/etc/passwd") # raises ValueErrorfrom nkit.interfaces import MemoryStore
class RedisMemory:
def get(self, key, default=None): ...
def set(self, key, value): ...
# Implement protocol methods
agent = Agent(llm=my_llm, memory=RedisMemory("redis://localhost"))from nkit.interfaces import RetrievalSystem
class VectorDBRetriever:
def retrieve(self, query, top_k=5, filters=None): ...
def add_documents(self, documents): ...
retriever = VectorDBRetriever(index="my-index")
prompt_service = RAGPromptService(retriever)
agent = Agent(llm=my_llm, prompt_service=prompt_service)# Basic graph demo
python nkit/examples/demo_graph.py
# RAG agent with persistent memory
python nkit/examples/demo_rag_agent.py- Python 3.10+
- Optional:
requests,aiohttpfor built-in web search tools
pip install requests aiohttp- ARCHITECTURE.md: Complete design documentation
- interfaces.py: Interface definitions with usage examples
- security.py: Security validators and best practices
Every module includes comprehensive docstrings explaining:
- Purpose: What the component does
- Reuse Patterns: How to use in different scenarios
- Security: What to watch out for
- Examples: Working code snippets
Problem:
"I want to plug and play a RAG system, or add a memory layer, with clean, secure, refactored code."
Solution:
- Plugin Architecture: Inject any component via constructor
- Interface-Based: Swap implementations without code changes
- Security Built-In: Validators, sanitizers, resource limits
- SOLID Compliance: Each component has one job, easily extensible
- Comprehensive Docs: Every function explains WHY and HOW
Result:
You can build a RAG Q&A agent with persistent memory and custom tools in ~20 lines, then swap to a vector DB and Redis backend by changing 2 parameters.
MIT
Issues and PRs welcome! See ARCHITECTURE.md for design guidelines.