Prefactor SDK
Prefactor SDK
Section titled “Prefactor SDK”Automatic observability for LangChain agents. Trace LLM calls, tool executions, and agent workflows with zero code changes.
Installation
Section titled “Installation”pip install prefactor-langchainQuick Start
Section titled “Quick Start”import astimport asyncioimport operatorfrom langchain.agents import create_agentfrom langchain_core.tools import toolfrom prefactor_langchain import PrefactorMiddleware
_OPS = {ast.Add: operator.add, ast.Sub: operator.sub, ast.Mult: operator.mul, ast.Div: operator.truediv}
def _safe_eval(node): if isinstance(node, ast.Constant): return node.n if isinstance(node, ast.BinOp): return _OPS[type(node.op)](_safe_eval(node.left), _safe_eval(node.right)) if isinstance(node, ast.UnaryOp) and isinstance(node.op, ast.USub): return -_safe_eval(node.operand) raise ValueError(f"Unsupported: {node}")
@tooldef calculator(expression: str) -> str: """Evaluate a mathematical expression safely.""" try: return str(_safe_eval(ast.parse(expression, mode='eval').body)) except Exception as e: return f"Error: {e}"
async def main(): middleware = PrefactorMiddleware.from_config( api_url="https://api.prefactor.ai", api_token="your-token", agent_id="my-agent", agent_name="My Agent", )
agent = create_agent( model="claude-haiku-4-5-20251001", tools=[calculator], middleware=[middleware], )
# All LLM calls and tool executions are automatically traced try: result = await agent.ainvoke({"messages": [{"role": "user", "content": "What is 6 * 7?"}]}) finally: await middleware.close()
asyncio.run(main())Features
Section titled “Features”- Automatic tracing of LLM calls with token usage
- Tool execution tracking
- Agent workflow visualization
- Parent-child span relationships
- Error tracking and debugging
- Zero-overhead instrumentation
Development Setup
Section titled “Development Setup”This project uses mise for reproducible development environments with the following tools:
- Python 3.11 with uv as the package manager
- ty for blazing-fast type checking (10-100x faster than mypy/pyright)
- ruff for linting and formatting (replaces Black, isort, Flake8, etc.)
- lefthook for git pre-commit hooks
Prerequisites
Section titled “Prerequisites”Install mise using one of these methods:
# macOS (Homebrew)brew install mise
# Linux/macOS (curl)curl https://mise.run | sh
# Other methods: https://mise.jdx.dev/getting-started.htmlAfter installation, activate mise in your shell:
# For bash (add to ~/.bashrc)eval "$(mise activate bash)"
# For zsh (add to ~/.zshrc)eval "$(mise activate zsh)"
# For fish (add to ~/.config/fish/config.fish)mise activate fish | sourceAlternatively, if you use direnv, mise will activate automatically when you enter the project directory.
Getting Started
Section titled “Getting Started”-
Clone the repository:
Terminal window git clone https://github.com/prefactordev/python-sdk.gitcd python-sdk -
Install project tools (Python, uv, ruff, etc.):
Terminal window mise install -
Set up the project (install dependencies and git hooks):
Terminal window mise run setupThis will:
- Create a virtual environment at
.venv - Install all dependencies via
uv sync --all-extras - Install git pre-commit hooks via lefthook
- Create a virtual environment at
-
You’re ready to develop! The virtual environment activates automatically when you enter the directory.
Common Tasks
Section titled “Common Tasks”# Run testsmise run test
# Run all quality checks (format, lint, typecheck)mise run check
# Individual checksmise run format # Format code with ruffmise run lint # Lint code with ruffmise run typecheck # Type check with ty
# Install/update dependenciesmise run installRunning Tests
Section titled “Running Tests”# Run all testspytest
# Run specific test filepytest packages/core/tests/test_client.py
# Run with verbose outputpytest -v
# Run specific testpytest packages/core/tests/test_client.py::TestClient::test_initialize -vPre-commit Hooks
Section titled “Pre-commit Hooks”Git pre-commit hooks run automatically on each commit via lefthook:
ruff format- Format staged Python filesruff check --fix- Lint and auto-fix staged Python filesuvx ty check- Type check the entire codebase
To run hooks manually:
lefthook run pre-commitVersioning
Section titled “Versioning”Package versions are defined in each package’s src/<package>/_version.py file.
That file is the single source of truth for both runtime __version__ and build
metadata.
packages/http/src/prefactor_http/_version.pypackages/core/src/prefactor_core/_version.pypackages/langchain/src/prefactor_langchain/_version.pypackages/livekit/src/prefactor_livekit/_version.py
Each package pyproject.toml uses Hatch dynamic versioning and reads the version
directly from that _version.py file. We do not resolve versions from installed
metadata or parse pyproject.toml at import time.
When bumping a package version:
- Update
__version__in that package’s_version.py. - Update any dependent package constraints if the new version requires it.
- Run
mise run testbefore committing.
Project Structure
Section titled “Project Structure”python-sdk/├── packages/│ ├── core/ # Core tracing and span lifecycle│ ├── http/ # HTTP client for the Prefactor API│ ├── langchain/ # LangChain instrumentation│ └── livekit/ # LiveKit instrumentation├── mise.toml # mise configuration├── lefthook.yml # Git hooks configuration└── pyproject.toml # Python project configuration (workspace root)Tools Reference
Section titled “Tools Reference”| Tool | Purpose | Documentation |
|---|---|---|
| mise | Tool version manager | Manages Python, uv, ruff, etc. |
| uv | Python package manager | Fast dependency resolution |
| ruff | Linter and formatter | Replaces Black, isort, Flake8 |
| ty | Type checker | 10-100x faster than mypy |
| lefthook | Git hooks manager | Runs pre-commit checks |
Claude Code Integration
Section titled “Claude Code Integration”If you use Claude Code, hooks are configured in .claude/settings.json:
- PostToolUse: Automatically formats and lints Python files after editing
- PreToolUse: Runs type checking before git commits