MIMORI SDK
Python package for sending AI agent telemetry to MIMORI. Works with any framework via drop-in handlers or manual logging.
Install
pip install -e ./sdk
Run from the cloned repository root. These examples target the source SDK; verify a published package's version and features separately. For development and tests:
pip install -e './sdk[dev]'
Install only the framework extras you need, preferably in a separate environment per agent. Some framework dependencies conflict when combined; there is no shared lockfile for all optional adapters. The commands here use pip (uv pip install also supports these source installs).
Quick Start
from mimori import MIMORIClient
client = MIMORIClient(
api_key="mmr_dev_...",
agent_name="my-agent",
api_url="http://localhost:3000",
)
client.log("llm_start", {"serialized": {"name": "gpt-4o"}, "prompts": ["Hello!"]})
client.log("llm_end", {"response": "Hi there!"})
client.close()
Framework Integrations
MIMORI provides 16 Python framework/provider adapters, a Vercel AI SDK source adapter, and direct instrumentation. Each handler translates the lifecycle hooks it observes into MIMORI telemetry events. See the integration matrix and verification scope: adapter mapping tests do not prove native compatibility with every upstream version.
For a framework-independent starting point, run the custom Python or Node.js examples. Guardrails and Laya are optional capabilities rather than additional framework integrations.
| Framework | Handler | Install | Event Mapping |
|---|---|---|---|
| LangChain | MIMORIHandler |
pip install -e './sdk[langchain]' |
Callbacks |
| CrewAI | MIMORICrewAIHandler |
pip install -e './sdk[crewai]' |
@on hooks |
| AutoGen / AG2 | MIMORIAutoGenHandler |
pip install -e './sdk[autogen]' |
register_hook() |
| LlamaIndex | MIMORILlamaIndexHandler |
pip install -e './sdk[llama-index]' |
BaseCallbackHandler |
| DSPy | MIMORIDSPyHandler |
pip install -e './sdk[dspy]' |
BaseCallback |
| OpenAI Agents SDK | MIMORIOpenAIAgentsHandler |
pip install -e './sdk[openai-agents]' |
TracingProcessor |
| Smolagents | MIMORISmolagentsHandler |
pip install -e './sdk[smolagents]' |
step_callbacks |
| Pydantic AI | MIMORIPydanticAIHandler |
pip install -e './sdk[pydantic-ai]' |
Hooks capability |
| LangGraph | MIMORILangGraphHandler |
pip install -e './sdk[langgraph]' |
Extends LangChain + GraphCallbackHandler |
| Google ADK | MIMORIGoogleADKHandler |
pip install -e './sdk[google-adk]' |
Agent callbacks |
| Semantic Kernel | MIMORISemanticKernelHandler |
pip install -e './sdk[semantic-kernel]' |
Filter middleware |
| Haystack | MIMORIHaystackHandler |
pip install -e './sdk[haystack]' |
@hook decorator |
| MetaGPT | MIMORIMetaGPTHandler |
pip install -e './sdk[metagpt]' |
Subclass wrapping |
| Agno (Phidata) | MIMORIAgnoHandler |
pip install -e './sdk[agno]' |
Pre/post hooks + tool middleware |
| Composio | MIMORIComposioHandler |
pip install -e './sdk[composio]' |
@before/after_execute |
| Anthropic Claude | MIMORIAnthropicHandler |
pip install -e './sdk[anthropic]' |
Client wrapper |
| Vercel AI SDK (JS) | MIMORIVercelAIHandler |
Copy sdk/mimori/vercel-ai-handler.js as .mjs |
generateTextConfig() |
| Active Guardrails & Laya | MIMORIGuardrail |
pip install -e './sdk[laya]' |
Pre-execution firewall |
| Direct / Manual SDK | MIMORIClient / log_event |
pip install -e ./sdk |
Python REST client |
LangChain
Install the adapter and current agent API from the repository root:
pip install -e './sdk[langchain]' 'langchain>=1,<2'
import os
from langchain.agents import create_agent
from mimori import MIMORIHandler
agent = create_agent(model="openai:gpt-4.1-mini", tools=tools)
with MIMORIHandler(
api_key=os.environ["MIMORI_API_KEY"],
agent_name="my-agent",
api_url="http://localhost:3000",
) as handler:
result = agent.invoke(
{"messages": [{"role": "user", "content": "Hello"}]},
config={"callbacks": [handler]},
)
# Flushes remaining telemetry on exit.
Use your existing tools and model configuration. This OpenAI example requires langchain-openai and OPENAI_API_KEY. Attach callbacks through invocation config so model and tool events propagate through the agent. For legacy AgentExecutor, pass the same invocation config to invoke.
Try the runnable synthetic fintech example without a cloud model key.
CrewAI
from mimori import MIMORICrewAIHandler
handler = MIMORICrewAIHandler(
api_key="mmr_dev_...",
agent_name="my-crew",
api_url="http://localhost:3000",
)
# Handler registers global @on hooks automatically
# Just run your crew normally
result = crew.kickoff()
handler.close()
AutoGen / AG2
from mimori import MIMORIAutoGenHandler
handler = MIMORIAutoGenHandler(
api_key="mmr_dev_...",
agent_name="my-agent",
api_url="http://localhost:3000",
)
# Register hooks on each agent
handler.register(assistant_agent)
handler.register(user_proxy)
# Run your conversation
assistant_agent.initiate_chat(user_proxy, message="Hello!")
handler.close()
LlamaIndex
from llama_index.core.callbacks import CallbackManager
from mimori import MIMORILlamaIndexHandler
handler = MIMORILlamaIndexHandler(
api_key="mmr_dev_...",
agent_name="my-index",
api_url="http://localhost:3000",
)
# Set globally
from llama_index.core import Settings
Settings.callback_manager = CallbackManager([handler])
# Or per-operation
query_engine = index.as_query_engine(callback_manager=CallbackManager([handler]))
response = query_engine.query("What is MIMORI?")
DSPy
import dspy
from mimori import MIMORIDSPyHandler
handler = MIMORIDSPyHandler(
api_key="mmr_dev_...",
agent_name="my-dspy-agent",
api_url="http://localhost:3000",
)
# Global
dspy.configure(callbacks=[handler])
# Or per-LM
lm = dspy.LM("openai/gpt-4o-mini", callbacks=[handler])
cot = dspy.ChainOfThought("question -> answer")
result = cot(question="What is 2+2?")
OpenAI Agents SDK
from agents import Runner, add_trace_processor, set_trace_processors
from mimori import MIMORIOpenAIAgentsHandler
handler = MIMORIOpenAIAgentsHandler(
api_key="mmr_dev_...",
agent_name="my-agent",
api_url="http://localhost:3000",
)
# Add alongside default OpenAI exporter
add_trace_processor(handler)
# Or replace default
set_trace_processors([handler])
result = Runner.run_sync(agent, "Hello!")
Smolagents
from smolagents import CodeAgent
from mimori import MIMORISmolagentsHandler
handler = MIMORISmolagentsHandler(
api_key="mmr_dev_...",
agent_name="my-agent",
api_url="http://localhost:3000",
)
agent = CodeAgent(
tools=[...],
model=model,
step_callbacks=[handler.step_callback],
before_tool_call_hooks=[handler.tool_hook],
)
result = agent.run("Do something")
handler.close()
Pydantic AI
from pydantic_ai import Agent
from mimori import MIMORIPydanticAIHandler
handler = MIMORIPydanticAIHandler(
api_key="mmr_dev_...",
agent_name="my-agent",
api_url="http://localhost:3000",
)
agent = Agent("openai:gpt-4o", capabilities=[handler.hooks])
result = agent.run_sync("Hello!")
handler.close()
LangGraph
from mimori import MIMORILangGraphHandler
handler = MIMORILangGraphHandler(
api_key="mmr_dev_...",
agent_name="my-graph",
api_url="http://localhost:3000",
)
# Pass via config at invocation time
result = graph.invoke(input, config={"callbacks": [handler]})
# Or attach to compiled graph
compiled = graph.compile().with_config(callbacks=[handler])
result = compiled.invoke(input)
Google ADK
from mimori import MIMORIGoogleADKHandler
handler = MIMORIGoogleADKHandler(
api_key="mmr_dev_...",
agent_name="my-adk-agent",
api_url="http://localhost:3000",
)
# Attach all callbacks at once
agent = handler.apply(agent)
# Or individually
agent = LlmAgent(
name="my_agent",
model="gemini-2.0-flash",
before_model_callback=handler.before_model,
after_model_callback=handler.after_model,
before_tool_callback=handler.before_tool,
after_tool_callback=handler.after_tool,
)
Semantic Kernel
from semantic_kernel import Kernel
from mimori import MIMORISemanticKernelHandler
handler = MIMORISemanticKernelHandler(
api_key="mmr_dev_...",
agent_name="my-sk-agent",
api_url="http://localhost:3000",
)
kernel = Kernel()
handler.apply(kernel)
result = await kernel.invoke_prompt("Hello!")
handler.close()
Haystack
from haystack.components.agents import Agent
from mimori import MIMORIHaystackHandler
handler = MIMORIHaystackHandler(
api_key="mmr_dev_...",
agent_name="my-agent",
api_url="http://localhost:3000",
)
agent = Agent(
chat_generator=OpenAIChatGenerator(model="gpt-4o"),
tools=[my_tool],
hooks=handler.hooks_dict(),
)
result = agent.run(messages=[ChatMessage.from_user("Hello!")])
handler.close()
MetaGPT
MetaGPT 0.8.2 pins an unavailable LanceDB release, so its normal optional-extra install currently fails upstream. The native Action test uses the explicit dependency override; it verifies Action wrapping only, not MetaGPT's LanceDB/RAG stack. See the version matrix.
from mimori import MIMORIMetaGPTHandler
handler = MIMORIMetaGPTHandler(
api_key="mmr_dev_...",
agent_name="my-metagpt-agent",
api_url="http://localhost:3000",
)
# Use the action decorator
@handler.wrap_action
class MyAction(Action):
async def run(self, *args, **kwargs):
return await super().run(*args, **kwargs)
handler.close()
Agno (Phidata)
from agno.agent import Agent
from mimori import MIMORIAgnoHandler
handler = MIMORIAgnoHandler(
api_key="mmr_dev_...",
agent_name="my-agent",
api_url="http://localhost:3000",
)
# Attach all hooks at once
agent = handler.apply(agent)
# Or individually
agent = Agent(
model=...,
tools=[...],
pre_hooks=[handler.pre_hook],
post_hooks=[handler.post_hook],
tool_hooks=[handler.tool_middleware],
)
agent.print_response("Hello!")
handler.close()
Composio
from composio import Composio
from mimori import MIMORIComposioHandler
handler = MIMORIComposioHandler(
api_key="mmr_dev_...",
agent_name="my-agent",
api_url="http://localhost:3000",
)
composio = Composio()
result = composio.tools.execute(
slug="GITHUB_CREATE_ISSUE",
arguments={"title": "Bug", "body": "..."},
user_id="user-123",
modifiers=handler.modifiers(),
)
handler.close()
Anthropic Claude SDK
import anthropic
from mimori import MIMORIAnthropicHandler
handler = MIMORIAnthropicHandler(
api_key="mmr_dev_...",
agent_name="my-agent",
api_url="http://localhost:3000",
)
# Wrap the client
client = handler.wrap(anthropic.Anthropic())
# Use normally — telemetry is captured
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=256,
messages=[{"role": "user", "content": "Hello!"}],
)
handler.close()
Vercel AI SDK
For TypeScript and JavaScript agents using the Vercel AI SDK, copy sdk/mimori/vercel-ai-handler.js into your project as mimori-vercel-ai.mjs. This adapter is distributed as a source file; there is no published npm SDK package:
import { MIMORIVercelAIHandler } from "./mimori-vercel-ai.mjs";
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
const handler = new MIMORIVercelAIHandler({
apiKey: "mmr_dev_...",
agentName: "my-vercel-agent",
apiUrl: "http://localhost:3000",
});
const result = await generateText({
model: openai("gpt-4o"),
prompt: "Hello!",
...handler.generateTextConfig(),
});
await handler.close(); // Drain pending telemetry before process shutdown.
Payload truncation (MAX_PAYLOAD_CHARS): the Vercel AI handler truncates
each captured string to MAX_PAYLOAD_CHARS (default 2000, exported from
the copied handler module). Python framework handlers truncate at 100_000
chars per string (_truncate(value, limit=100_000); MIMORIConfig
documents max_payload_chars defaulting to 100_000). The budgets
intentionally differ by runtime (browser/edge payloads vs. server-side
Python) — do not assume parity.
Active Guardrails
Check known threat patterns before tool execution by explicitly wrapping each protected tool. These checks have limited coverage and must be evaluated against your workloads:
from mimori import MIMORIGuardrail, SecurityViolation
guard = MIMORIGuardrail(mode="block")
# Protect a tool function
@guard.protect_tool
def execute_database_query(sql: str):
return db.query(sql)
# Evaluate prompt directly (bounded regex pass; no timing guarantee)
verdict = guard.evaluate(user_prompt)
if not verdict.allowed:
print(f"Blocked: {verdict.reason}")
Tool-response review and task authorization
For indirect prompt injection, review external content against the original task before the agent reads it. The opt-in semantic path reviews every response and blocks failed reviews in block mode:
from mimori import MIMORIGuardrail, OllamaSecurityReviewer
guard = MIMORIGuardrail(mode="block")
reviewer = OllamaSecurityReviewer(model="llama3.1:latest", timeout=120) # Local model must be installed.
guard.verify_tool_response(
tool_output,
user_request=original_user_request, # From trusted application task state.
reviewer=reviewer,
tool_name="read_page",
)
Use protect_tool_result to review a read tool's return value, and protect_tool(..., authorize=...) or ToolCapabilityPolicy to check action permissions before execution. A semantic allow decision does not authorize a new action. LangChain and LangGraph handlers accept opt-in review and authorization configuration; telemetry-only use retains its existing behavior. See setup, examples, and measured limits.
LayeredSecurityReviewer(semantic=reviewer, laya=LayaSecurityReviewer()) optionally adds the experimental local Laya checkpoint. It requires real model inference, refuses heuristic fallback, and keeps semantic review mandatory. Either layer may block; failures are evaluation errors. Benchmark recall, false positives and latency before enabling it. See Laya setup and the independent-layer comparison.
Laya-Enhanced Guardrails
Enable the optional Laya classifier for an additional signal beyond regex. Model scores are not validated or calibrated for your workload; evaluate the model before using its output to block wrapped operations.
pip install -e './sdk[laya]'
from mimori import MIMORIGuardrail, LayaClassifier
# Quick start — uses default Laya at localhost:5050
guard = MIMORIGuardrail(mode="block", use_classifier=True)
# Custom classifier configuration
guard = MIMORIGuardrail(
mode="block",
use_classifier=True,
classifier=LayaClassifier(
base_url="http://my-laya-host:5050",
model="convaiinnovations/laya-large",
threshold=0.8, # Minimum classifier score to block (default: 0.75)
timeout=2.0, # Request timeout in seconds (default: 2.0)
),
)
# Regex checks known patterns first; Laya classifies remaining inputs
verdict = guard.evaluate(user_prompt)
How it works: evaluate() first runs regex rules over overlapping chunks of the input, with normalized views for instruction patterns. Inputs over 1,000,000 characters return a violation; block mode prevents wrapped tool execution. Matches spanning more than the 2,500-character overlap can require custom validation. If no regex match is found and use_classifier=True, it calls the optional Laya service. The bundled service uses a heuristic fallback unless a compatible checkpoint is supplied. If the service is unreachable, an otherwise unmatched input is allowed; existing regex matches and evaluation limits still apply.
Manual Logging
For frameworks without a built-in handler, use the manual logging helper:
from mimori import log_event
log_event(
api_key="mmr_dev_...",
agent_name="my-custom-agent",
event_type="tool_start",
payload={"tool": {"name": "calculator"}, "input": "2 + 2"},
api_url="http://localhost:3000",
)
Client caching: Each unique (api_key, agent_name, session_id, api_url) combination creates a cached MIMORIClient with a background flush thread. Clients are flushed and closed on process exit via atexit. If you call log_event() with many different session_id values, each creates a separate background thread.
Event Payload Schemas
If you are logging manually, use these recommended JSON structures for the payload object to ensure events render correctly in the dashboard:
| Event Type | Expected payload Keys |
Example |
|---|---|---|
llm_start |
serialized (dict), prompts (list) |
{"serialized": {"name": "gpt-4o"}, "prompts": ["Hello!"]} |
llm_end |
response (any) |
{"response": "Hi there!"} |
tool_start |
tool (dict), input (any) |
{"tool": {"name": "calculator"}, "input": "2 + 2"} |
tool_end |
output (any) |
{"output": "4"} |
chain_start |
chain (dict), inputs (dict) |
{"chain": {"name": "my-chain"}, "inputs": {"query": "test"}} |
chain_end |
outputs (dict) |
{"outputs": {"answer": "result"}} |
agent_action |
action (any) |
{"action": "Agent decided to use calculator"} |
manual |
Freeform | {"message": "Agent workflow started."} |
The SDK batches telemetry in a background thread and fails open if MIMORI is unreachable. It is designed to avoid disrupting agent execution, so it must not be the sole audit trail for security-critical operations.
Metadata
Release files for mimori-sdk 1.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mimori_sdk-1.1.0.tar.gz | 93.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mimori_sdk-1.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 160.8 kB
Release files / mimori_sdk-1.1.0.tar.gz
| Download URL | mimori_sdk-1.1.0.tar.gz |
|---|---|
| Size | 93.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
3b47f338c0686bac06385f3e8dd7eac5bfeecf7c9b30ce523de06df37d5f99bc
|
|
BLAKE2b-256 checksum How to use checksums |
0581361388eb47a35a9f717bbc1c30c0dba43c619a422b00eae6ed13e19278db
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / mimori_sdk-1.1.0-py3-none-any.whl
| Download URL | mimori_sdk-1.1.0-py3-none-any.whl |
|---|---|
| Size | 67.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9877ec38559fa2ab24ae9a2a388e181ccaf4ed8b1538a8edacbbe35e0f141b82
|
|
BLAKE2b-256 checksum How to use checksums |
69b22491c3eb56b662355ffdc8b8ddc227d6c77ebcab10d077ef6538b820b737
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|