[build-system] requires = ["setuptools>=68", "wheel"] build-backend = "setuptools.build_meta" [project] # Distribution name on PyPI. NOT "ai-r": PyPI folds separators and look-alike # chars (l/i→1, o→0) when checking for typosquats, so "ai-r" collapses to "air", # an existing project, and is rejected. "ai-reader" is registered by someone # else. The CLI commands (ai-r, ai-r-mcp) and the import package (ai_r) are # unaffected by the distribution name. name = "agent-session-reader" version = "0.4.2" description = "Multi-agent session reader (Claude, Codex, OpenCode, Antigravity, Pi) with MCP server" readme = "README.md" license = {text = "MIT"} requires-python = ">=3.11" authors = [ {name = "Dmitrii Makarov", email = "wm-k@mail.ru"}, ] keywords = ["mcp", "agent", "session", "reader", "multi-agent"] classifiers = [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Topic :: Software Development :: Libraries", ] dependencies = [ # 1.9.0 is the floor that ships the streamable-http transport # (``FastMCP.streamable_http_app``) and native transport-security # (``TransportSecuritySettings``: DNS-rebinding Origin/Host validation) # that ``ai_r.serve.run_http`` relies on. Older SDKs lack these APIs, so # the http transport would crash at import/call time. "mcp>=1.9.0", ] [project.optional-dependencies] # Better token *estimates* for sessions whose format stores no exact usage # numbers (F3.3). Fully optional: without it ai-r falls back to a rough # chars/4 heuristic, honestly labeled — never a crash. tokens = [ "tiktoken>=0.5", ] # Meaning-aware search (F5.1): sort="semantic" re-ranks the BM25 top-50 # candidates with a local multilingual embedding model # (intfloat/multilingual-e5-small, int8 ONNX ~118 MB, run directly via # onnxruntime + tokenizers — no torch). Model files are downloaded by # `AI_R_EXTRAS=semantic bash install.sh` (or manually, see README). # Fully optional: without these packages or the model files semantic sort # honestly degrades to the plain BM25 order with a reason — never a crash. semantic = [ "onnxruntime>=1.17", "tokenizers>=0.15", "numpy>=1.24", ] # Shared streamable-http MCP transport (`AI_R_MCP_TRANSPORT=http`): one # long-lived localhost server instead of a per-agent stdio swarm. Fully # optional — the default stdio transport needs nothing here. `uvicorn` is # imported lazily inside `ai_r.serve.run_http`, so stdio users never load it. http = [ "uvicorn>=0.30", ] dev = [ "pytest>=8.0", "pytest-cov>=4.1", "pytest-asyncio>=0.23", # Property-based fuzzing of the parsers (tests/test_fuzz_parsers.py): they # are the ingestion point for untrusted transcripts, so the fail-soft # contract is asserted against generated corrupt input, not hand-picked # samples. Dev-only — never imported by the package at runtime. "hypothesis>=6.100", "mypy>=1.8", "ruff>=0.6", ] [project.scripts] ai-r = "ai_r.cli:main" ai-r-mcp = "ai_r.mcp_server:main" [project.urls] Homepage = "https://github.com/pro-target/ai-r" Issues = "https://github.com/pro-target/ai-r/issues" [tool.setuptools.packages.find] where = ["src"] [tool.pytest.ini_options] testpaths = ["tests"] # Resolve ``ai_r`` from the working tree, never a stale site-packages wheel: # ``pytest`` prepends these to ``sys.path`` so ``make test-hermetic`` targets # the source under edit regardless of what ``pip install`` left installed. pythonpath = ["src"] addopts = "-v --tb=short" asyncio_mode = "auto" markers = [ "host: test reads real ~/.claude|.codex|opencode|.pi|.gemini data; auto-applied to any test using a real_* fixture; skipped when absent and deselected by the hermetic CI job", ] [tool.coverage.run] source = ["src/ai_r"] omit = ["*/tests/*", "*/__pycache__/*"] [tool.coverage.report] exclude_lines = [ "pragma: no cover", "if __name__ == .__main__.:", ] fail_under = 85 # Lint config — lenient by design so `ruff check` / `mypy src` run clean on # the current codebase and tighten incrementally. Enforced in CI (the `lint` # job runs `ruff check src/` + `mypy src/`). [tool.ruff] line-length = 100 target-version = "py311" extend-exclude = ["build", "dist", ".venv", "site-packages"] [tool.ruff.lint] # Pyflakes (real bugs: unused imports, undefined names) + syntax errors only. select = ["F", "E9"] [tool.mypy] python_version = "3.12" ignore_missing_imports = true warn_unused_ignores = true # Type-check the bodies of unannotated functions too (audit: without this # mypy silently skips them). Verified clean across src/, so it is now enforced. check_untyped_defs = true