leancontext 2.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- leancontext-2.0.0/.editorconfig +17 -0
- leancontext-2.0.0/.github/CODEOWNERS +2 -0
- leancontext-2.0.0/.github/ISSUE_TEMPLATE/bug_report.md +25 -0
- leancontext-2.0.0/.github/ISSUE_TEMPLATE/config.yml +1 -0
- leancontext-2.0.0/.github/ISSUE_TEMPLATE/feature_request.md +16 -0
- leancontext-2.0.0/.github/PULL_REQUEST_TEMPLATE.md +12 -0
- leancontext-2.0.0/.github/dependabot.yml +10 -0
- leancontext-2.0.0/.github/workflows/ci.yml +30 -0
- leancontext-2.0.0/.github/workflows/publish.yml +28 -0
- leancontext-2.0.0/.gitignore +29 -0
- leancontext-2.0.0/.pre-commit-config.yaml +12 -0
- leancontext-2.0.0/AGENTS.md +174 -0
- leancontext-2.0.0/CHANGELOG.md +32 -0
- leancontext-2.0.0/CITATION.cff +19 -0
- leancontext-2.0.0/CODE_OF_CONDUCT.md +54 -0
- leancontext-2.0.0/CONTRIBUTING.md +48 -0
- leancontext-2.0.0/LICENSE +190 -0
- leancontext-2.0.0/PKG-INFO +224 -0
- leancontext-2.0.0/README.md +182 -0
- leancontext-2.0.0/RELEASING.md +45 -0
- leancontext-2.0.0/SECURITY.md +22 -0
- leancontext-2.0.0/assets/logo.png +0 -0
- leancontext-2.0.0/assets/logo.svg +22 -0
- leancontext-2.0.0/bench.py +84 -0
- leancontext-2.0.0/demo.py +65 -0
- leancontext-2.0.0/docs/ARCHITECTURE.md +99 -0
- leancontext-2.0.0/examples/basic_usage.py +42 -0
- leancontext-2.0.0/examples/validate_caching.py +140 -0
- leancontext-2.0.0/leancontext/__init__.py +104 -0
- leancontext-2.0.0/leancontext/cli.py +36 -0
- leancontext-2.0.0/leancontext/core.py +214 -0
- leancontext-2.0.0/leancontext/cost.py +104 -0
- leancontext-2.0.0/leancontext/fidelity.py +108 -0
- leancontext-2.0.0/leancontext/integrations/__init__.py +8 -0
- leancontext-2.0.0/leancontext/integrations/_common.py +62 -0
- leancontext-2.0.0/leancontext/integrations/anthropic_native.py +83 -0
- leancontext-2.0.0/leancontext/integrations/clients.py +58 -0
- leancontext-2.0.0/leancontext/integrations/decorator.py +103 -0
- leancontext-2.0.0/leancontext/integrations/frameworks.py +58 -0
- leancontext-2.0.0/leancontext/integrations/litellm.py +80 -0
- leancontext-2.0.0/leancontext/integrations/mcp_server.py +64 -0
- leancontext-2.0.0/leancontext/integrations/otel.py +78 -0
- leancontext-2.0.0/leancontext/integrations/proxy.py +90 -0
- leancontext-2.0.0/leancontext/messages.py +152 -0
- leancontext-2.0.0/leancontext/paging.py +104 -0
- leancontext-2.0.0/leancontext/py.typed +0 -0
- leancontext-2.0.0/leancontext/reducers/__init__.py +36 -0
- leancontext-2.0.0/leancontext/reducers/base.py +19 -0
- leancontext-2.0.0/leancontext/reducers/diff.py +54 -0
- leancontext-2.0.0/leancontext/reducers/html.py +64 -0
- leancontext-2.0.0/leancontext/reducers/json_data.py +61 -0
- leancontext-2.0.0/leancontext/reducers/logs.py +91 -0
- leancontext-2.0.0/leancontext/reducers/stacktrace.py +59 -0
- leancontext-2.0.0/leancontext/reducers/table.py +32 -0
- leancontext-2.0.0/leancontext/tokens.py +79 -0
- leancontext-2.0.0/pyproject.toml +63 -0
- leancontext-2.0.0/tests/test_cache.py +63 -0
- leancontext-2.0.0/tests/test_core.py +67 -0
- leancontext-2.0.0/tests/test_differentiators.py +92 -0
- leancontext-2.0.0/tests/test_fidelity.py +36 -0
- leancontext-2.0.0/tests/test_frameworks.py +97 -0
- leancontext-2.0.0/tests/test_gateway.py +118 -0
- leancontext-2.0.0/tests/test_gemini.py +75 -0
- leancontext-2.0.0/tests/test_limits.py +27 -0
- leancontext-2.0.0/tests/test_mcp.py +34 -0
- leancontext-2.0.0/tests/test_messages.py +66 -0
- leancontext-2.0.0/tests/test_otel.py +70 -0
- leancontext-2.0.0/tests/test_paging.py +46 -0
- leancontext-2.0.0/tests/test_proxy.py +59 -0
- leancontext-2.0.0/tests/test_reducers.py +64 -0
- leancontext-2.0.0/tests/test_table.py +32 -0
- leancontext-2.0.0/tests/test_tokens.py +22 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
trim_trailing_whitespace = true
|
|
8
|
+
indent_style = space
|
|
9
|
+
|
|
10
|
+
[*.py]
|
|
11
|
+
indent_size = 4
|
|
12
|
+
|
|
13
|
+
[*.{yml,yaml,toml,json}]
|
|
14
|
+
indent_size = 2
|
|
15
|
+
|
|
16
|
+
[*.md]
|
|
17
|
+
trim_trailing_whitespace = false
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Something isn't working as expected
|
|
4
|
+
title: ""
|
|
5
|
+
labels: bug
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
**What happened**
|
|
9
|
+
A clear description of the bug.
|
|
10
|
+
|
|
11
|
+
**To reproduce**
|
|
12
|
+
A minimal snippet, ideally the payload and the call:
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
import leancontext
|
|
16
|
+
r = leancontext.reduce(...)
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
**Expected**
|
|
20
|
+
What you expected instead.
|
|
21
|
+
|
|
22
|
+
**Environment**
|
|
23
|
+
- LeanContext version:
|
|
24
|
+
- Python version:
|
|
25
|
+
- OS:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest an improvement (a new reducer, integration, etc.)
|
|
4
|
+
title: ""
|
|
5
|
+
labels: enhancement
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
**The problem**
|
|
9
|
+
What are you trying to do, and what's missing today?
|
|
10
|
+
|
|
11
|
+
**Proposed solution**
|
|
12
|
+
What you'd like to see. For a new reducer, include a sample payload and what should
|
|
13
|
+
be kept vs. collapsed.
|
|
14
|
+
|
|
15
|
+
**Alternatives**
|
|
16
|
+
Anything you've considered or worked around.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
## What this changes
|
|
2
|
+
|
|
3
|
+
A short description of the change and why.
|
|
4
|
+
|
|
5
|
+
## Checklist
|
|
6
|
+
|
|
7
|
+
- [ ] `ruff check leancontext` passes
|
|
8
|
+
- [ ] `mypy leancontext` passes
|
|
9
|
+
- [ ] `pytest -q` passes
|
|
10
|
+
- [ ] New behavior has tests
|
|
11
|
+
- [ ] Reducers stay deterministic and value-preserving (see `AGENTS.md`)
|
|
12
|
+
- [ ] `CHANGELOG.md` updated if user-facing
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
fail-fast: false
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.14"]
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
- uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: ${{ matrix.python-version }}
|
|
21
|
+
- name: Install
|
|
22
|
+
run: |
|
|
23
|
+
python -m pip install --upgrade pip
|
|
24
|
+
pip install -e ".[dev,otel,integrations,mcp]"
|
|
25
|
+
- name: Lint (ruff)
|
|
26
|
+
run: ruff check leancontext bench.py demo.py
|
|
27
|
+
- name: Type check (mypy)
|
|
28
|
+
run: mypy leancontext
|
|
29
|
+
- name: Tests
|
|
30
|
+
run: pytest -q --cov=leancontext --cov-report=term-missing
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
# Publishes automatically when you create a GitHub Release.
|
|
4
|
+
# Uses PyPI Trusted Publishing (OIDC) — no API tokens needed.
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
release:
|
|
8
|
+
types: [published]
|
|
9
|
+
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
publish:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
permissions:
|
|
17
|
+
id-token: write # required for Trusted Publishing
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.14"
|
|
23
|
+
- name: Build sdist and wheel
|
|
24
|
+
run: |
|
|
25
|
+
python -m pip install --upgrade build
|
|
26
|
+
python -m build
|
|
27
|
+
- name: Publish to PyPI
|
|
28
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
.eggs/
|
|
6
|
+
build/
|
|
7
|
+
dist/
|
|
8
|
+
*.so
|
|
9
|
+
|
|
10
|
+
# Virtual envs
|
|
11
|
+
.venv/
|
|
12
|
+
venv/
|
|
13
|
+
env/
|
|
14
|
+
|
|
15
|
+
# Tooling caches
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.mypy_cache/
|
|
18
|
+
.ruff_cache/
|
|
19
|
+
.coverage
|
|
20
|
+
htmlcov/
|
|
21
|
+
|
|
22
|
+
# OS / editor
|
|
23
|
+
.DS_Store
|
|
24
|
+
.idea/
|
|
25
|
+
.vscode/
|
|
26
|
+
*.swp
|
|
27
|
+
|
|
28
|
+
# Local content store (paging)
|
|
29
|
+
.leancontext/
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.15.8
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
7
|
+
rev: v5.0.0
|
|
8
|
+
hooks:
|
|
9
|
+
- id: trailing-whitespace
|
|
10
|
+
- id: end-of-file-fixer
|
|
11
|
+
- id: check-yaml
|
|
12
|
+
- id: check-toml
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# AGENTS.md — LeanContext
|
|
2
|
+
|
|
3
|
+
> Project name: **LeanContext** — keep agent context lean (drop redundant boilerplate, keep the signal). Easy to rename.
|
|
4
|
+
> This file is the contract for any human or AI agent working in this repo. Read it before writing code.
|
|
5
|
+
|
|
6
|
+
## 1. Mission
|
|
7
|
+
|
|
8
|
+
Cut the cost of agentic LLM workflows by shrinking **what we send to the model**, without
|
|
9
|
+
making the agent do less. The cost driver is *input tokens* — tool outputs, log dumps, RAG
|
|
10
|
+
chunks, and JSON responses that arrive raw (repeated keys, boilerplate, verbose formatting)
|
|
11
|
+
and are then **re-sent on every turn** (the quadratic tax).
|
|
12
|
+
|
|
13
|
+
We reduce that payload **at the source** — the moment a tool result is produced — where its
|
|
14
|
+
structure is still known. Deterministic, type-aware, cache-stable, and with **measurable
|
|
15
|
+
fidelity** so teams can trust it in production.
|
|
16
|
+
|
|
17
|
+
**Three pillars (our verified edge vs the incumbent Headroom — see §11):**
|
|
18
|
+
1. **Cache-safe by construction** — deterministic + content-addressed, so we never break the
|
|
19
|
+
provider prompt-cache discount (Headroom's cache benefit is conditional).
|
|
20
|
+
2. **Measurable fidelity** — a safety score on *every* reduction, not just dataset-level aggregates.
|
|
21
|
+
3. **Provider-native interop** — composes with Anthropic context-editing / compaction / memory tool
|
|
22
|
+
and LiteLLM, instead of replacing them. Zero ML in the path (no overhead, no language bias).
|
|
23
|
+
|
|
24
|
+
## 2. The problem (settled)
|
|
25
|
+
|
|
26
|
+
- The cost is the **input**, not the model output (input is typically 10–50× output in coding agents).
|
|
27
|
+
- A tool output added on turn N is paid for again on every later turn → **O(n²)**.
|
|
28
|
+
- Raw payloads are mostly redundancy: repeated timestamps, JSON keys, boilerplate, near-identical lines.
|
|
29
|
+
|
|
30
|
+
## 3. Why existing "compress-on-the-wire" middleware falls short
|
|
31
|
+
|
|
32
|
+
These are the gaps LeanContext is designed to beat. Do not reintroduce them.
|
|
33
|
+
|
|
34
|
+
| Gap | Their failure | Our fix |
|
|
35
|
+
|-----|---------------|---------|
|
|
36
|
+
| Structure-blind | Compresses a flattened request blob; can't tell a log from RAG | Reduce at the **tool-result boundary**, type-aware |
|
|
37
|
+
| Still O(n²) | Compresses but re-sends every turn | Optional **paging**: aged results → expandable refs (O(1)) |
|
|
38
|
+
| Breaks prompt caching | Non-deterministic / cross-context compression busts the prefix cache | **Deterministic + content-addressed** → cache-stable |
|
|
39
|
+
| Reversibility helps humans, not the agent | Model only sees compressed text, can't ask for detail | Paging gives the agent an `expand` handle |
|
|
40
|
+
| No measurable safety | "usually keeps the signal" is a probability | **Fidelity score** per reduction |
|
|
41
|
+
| Re-compress churn | Re-runs every turn | Reduce **once**, cache by content hash |
|
|
42
|
+
| Value loss | Drops an exact ID/number the agent needed | **Value-preserving** reducers |
|
|
43
|
+
|
|
44
|
+
## 4. Design principles (non-negotiable)
|
|
45
|
+
|
|
46
|
+
1. **Reduce at the source, not the wire.** Structure = safety + ratio.
|
|
47
|
+
2. **No LLM in the reduction path.** Deterministic, microsecond-scale, debuggable, free.
|
|
48
|
+
3. **Deterministic & content-addressed.** Same input → same output → stays cacheable.
|
|
49
|
+
4. **Anomaly-preserving.** The rare line *is* the signal. Frequency-1 patterns and
|
|
50
|
+
error/warn/exception lines are kept verbatim.
|
|
51
|
+
5. **Value-preserving.** Never silently drop identifiers, numbers, paths, or quoted values
|
|
52
|
+
that could be load-bearing for the agent's reasoning.
|
|
53
|
+
6. **Measurable safety.** Every reduction reports a fidelity score and what it preserved/dropped.
|
|
54
|
+
7. **Non-invasive by default.** `@reduce` decorator / tool wrapper. Paging is opt-in.
|
|
55
|
+
8. **Honest accounting.** Report tokens before/after *and* cache-aware cost estimate.
|
|
56
|
+
|
|
57
|
+
## 5. Integration & adoption (the make-or-break)
|
|
58
|
+
|
|
59
|
+
Adoption dies on two things: **friction** and **fear**. These rules kill both.
|
|
60
|
+
|
|
61
|
+
**A. Tiered integration — pick your friction level. All routes share one core.**
|
|
62
|
+
1. Manual: `reduce(text).text` — zero coupling, works literally anywhere.
|
|
63
|
+
2. Decorator: `@reduce` on a tool function — one line per tool.
|
|
64
|
+
3. Bulk wrap: `tools = leancontext.wrap(tools)` — one line for all tools; detects LangChain/OpenAI/CrewAI tool objects and plain callables.
|
|
65
|
+
4. Client fallback: `client = leancontext.wrap(openai_client)` — when you can't touch the tools (structure-blind, last resort).
|
|
66
|
+
|
|
67
|
+
**B. Target the tool *callable*, not the framework.** Every framework ultimately invokes a Python
|
|
68
|
+
callable for a tool. Operating on the callable's return value is universal — no per-framework code.
|
|
69
|
+
|
|
70
|
+
**C. Fail open, ALWAYS.** Never break the agent. If the type is unknown, the reducer errors, the
|
|
71
|
+
saving is below threshold, or fidelity is below threshold → return the **original, unchanged**.
|
|
72
|
+
LeanContext can only ever help or no-op. This is the single most important rule.
|
|
73
|
+
|
|
74
|
+
**D. Preserve the tool contract.** Same signature, same return type (`str` in → `str` out).
|
|
75
|
+
The agent never knows LeanContext exists. No new required params, no behavior change.
|
|
76
|
+
|
|
77
|
+
**E. Zero config, sane defaults.** `pip install leancontext`, add one line. No setup, no keys, no service.
|
|
78
|
+
|
|
79
|
+
**F. Global kill switch.** `LEANCONTEXT_DISABLED=1` (env) or `leancontext.disable()` instantly no-ops
|
|
80
|
+
everything — the trust lever teams need during an incident.
|
|
81
|
+
|
|
82
|
+
**G. Silent by default, observable on demand.** No logging unless a hook is attached
|
|
83
|
+
(`leancontext.on_reduction(cb)` for savings telemetry). Never spams stdout.
|
|
84
|
+
|
|
85
|
+
**H. No forced dependencies.** Core is stdlib-only. Real tokenizers (tiktoken) and framework
|
|
86
|
+
adapters are optional extras.
|
|
87
|
+
|
|
88
|
+
## 6. Non-goals
|
|
89
|
+
|
|
90
|
+
- Not a hosted service or dashboard. Local-first, library-first.
|
|
91
|
+
- Not a model router or gateway (compose with LiteLLM etc., don't replace them).
|
|
92
|
+
- Not lossy "summarization by an LLM" (that costs tokens to save tokens, and is non-deterministic).
|
|
93
|
+
- Not a memory framework (compose with the agent's own history management).
|
|
94
|
+
|
|
95
|
+
## 7. Architecture
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
leancontext/
|
|
99
|
+
__init__.py # public API: reduce(), Reduction, reduce decorator
|
|
100
|
+
core.py # dispatch, type detection, Reduction dataclass, token counting
|
|
101
|
+
fidelity.py # salience extraction + fidelity scoring
|
|
102
|
+
tokens.py # pluggable token counter (heuristic default, optional tiktoken)
|
|
103
|
+
reducers/
|
|
104
|
+
__init__.py
|
|
105
|
+
logs.py # collapse near-identical lines, keep anomalies/errors verbatim
|
|
106
|
+
json_data.py # factor schema once, send rows as values (columnar)
|
|
107
|
+
diff.py # keep changed hunks, reference unchanged (later)
|
|
108
|
+
stacktrace.py # keep frames at the boundary + the cause (later)
|
|
109
|
+
integrations/
|
|
110
|
+
decorator.py # @reduce for tool functions
|
|
111
|
+
client.py # provider client wrapper (fallback surface) (later)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Public API (stable target):
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from leancontext import reduce
|
|
118
|
+
|
|
119
|
+
r = reduce(tool_output) # kind auto-detected
|
|
120
|
+
r.text # reduced string to send to the model
|
|
121
|
+
r.tokens_before, r.tokens_after # honest accounting
|
|
122
|
+
r.ratio # 0.0–1.0 saved
|
|
123
|
+
r.fidelity # 0.0–1.0 signal preserved
|
|
124
|
+
r.kind, r.notes, r.ref # type, human notes, content hash (for paging)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
from leancontext import reduce as reduce_tool
|
|
129
|
+
|
|
130
|
+
@reduce_tool # non-invasive integration
|
|
131
|
+
def search_logs(query: str) -> str:
|
|
132
|
+
...
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## 8. Conventions
|
|
136
|
+
|
|
137
|
+
- Python 3.14+. Standard library only in the core path; optional extras (tiktoken) behind a flag.
|
|
138
|
+
- Type hints everywhere. Dataclasses for results.
|
|
139
|
+
- Pure functions for reducers: `reduce(text, **opts) -> Reduction`. No global state, no I/O.
|
|
140
|
+
- Determinism is a test requirement: same input must yield byte-identical output.
|
|
141
|
+
- Every reducer ships with: a fidelity guarantee, a docstring stating what it preserves, and tests.
|
|
142
|
+
|
|
143
|
+
## 9. Testing
|
|
144
|
+
|
|
145
|
+
- `pytest`. Each reducer: ratio test (achieves target on representative input), determinism test,
|
|
146
|
+
and a fidelity test (known salient tokens survive).
|
|
147
|
+
- A golden "incident log" fixture is the canonical demo: a ~10k-token log with one FATAL line
|
|
148
|
+
must reduce hard while preserving the FATAL line and all distinct error templates.
|
|
149
|
+
|
|
150
|
+
## 10. Roadmap
|
|
151
|
+
|
|
152
|
+
- **v0 (now):** core dispatch + `logs` + `json_data` reducers, fidelity, token accounting, `@reduce`, demo.
|
|
153
|
+
- **v0.1:** `diff`, `stacktrace`, `table`, `html` reducers; tiktoken integration; CLI (`leancontext reduce <file>`).
|
|
154
|
+
- **v0.2:** opt-in paging tier (`expand` tool + content store); client-wrapper fallback surface.
|
|
155
|
+
- **v0.3:** framework adapters (LangChain/LlamaIndex/CrewAI tool wrappers); cost report.
|
|
156
|
+
|
|
157
|
+
## 11. Differentiation — evidence-based (vs Headroom, verified 2026-06-21)
|
|
158
|
+
|
|
159
|
+
Headroom (github.com/chopratejas/headroom, Apache-2.0, v0.26.0) is the reference incumbent and is
|
|
160
|
+
genuinely strong: library + proxy + MCP + CCR reversible retrieval, hybrid statistical+ML compression.
|
|
161
|
+
|
|
162
|
+
**Non-clone rule (crucial):** we do NOT re-implement Headroom. Where it is strong (Rust "SmartCrusher"
|
|
163
|
+
statistical JSON, AST-aware code compaction, ML "Kompress"), we either match with a *standard*
|
|
164
|
+
(e.g. TOON for structured data, later) or defer. We compete ONLY on its **verified gaps** below.
|
|
165
|
+
|
|
166
|
+
| Verified gap in Headroom | LeanContext's edge |
|
|
167
|
+
|---|---|
|
|
168
|
+
| No interop with provider-native context mgmt (Anthropic `clear_tool_uses` / compaction / memory tool) | Compose with them: compress on ingest, provider clears on age. Cross-provider. |
|
|
169
|
+
| No per-reduction fidelity score (only dataset-level aggregates) | Fidelity score on every reduction; fail-open below threshold. |
|
|
170
|
+
| Prompt-cache benefit is conditional (changing prefixes erase KV-cache savings) | Cache-safe by construction: deterministic, per-block, content-addressed → reduce once, stable bytes. |
|
|
171
|
+
| Hybrid uses ML (Kompress): overhead, English-biased, net-negative on fast models | Zero-ML, deterministic → no model load, no language bias, never net-negative. |
|
|
172
|
+
| RAG document text + small/under-threshold payloads pass through | (Roadmap) optionally reduce RAG document blocks safely. |
|
|
173
|
+
| Reversibility bounded by TTL + local LRU (RAM cost) | Determinism lets us re-derive instead of store; lighter retrieval. |
|
|
174
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here. The format is based on
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/), and the project aims to follow semantic versioning.
|
|
5
|
+
|
|
6
|
+
## [Unreleased]
|
|
7
|
+
|
|
8
|
+
## [2.0.0] - 2026-06-21
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Core fail-open reduction pipeline with deterministic output and per-content-type
|
|
12
|
+
fidelity scoring (json, diff, and stack-trace reductions are verified, not assumed).
|
|
13
|
+
- Reducers: `log`, `json`, `diff`, `stacktrace`, `html`, and `table` (whitespace-aligned
|
|
14
|
+
command-line output). Each reducer declares its own detector via a small registry.
|
|
15
|
+
- Content-addressed cross-turn cache (each unique payload is reduced once).
|
|
16
|
+
- Integrations: `@reduce` decorator and `wrap()` (sync and async tools); OpenAI / Anthropic /
|
|
17
|
+
Gemini client wrappers; `reduce_messages` (OpenAI, Anthropic, Gemini formats); LiteLLM
|
|
18
|
+
proxy + SDK; a hardened standalone FastAPI proxy (auth passthrough, streaming, 502 on
|
|
19
|
+
upstream errors); OpenTelemetry telemetry; Anthropic native context-editing interop;
|
|
20
|
+
an MCP server (`reduce`/`expand`/`stats`); and framework adapters for LangChain,
|
|
21
|
+
LangGraph, and Agno.
|
|
22
|
+
- Cost accounting (`CostTracker`, `estimate_savings`) and paging (`lc://` references + `expand`).
|
|
23
|
+
- Token counting auto-uses `tiktoken` when installed, with `active_tokenizer()` to report it.
|
|
24
|
+
- A caching-on validation harness (`examples/validate_caching.py`) for Anthropic and OpenAI.
|
|
25
|
+
- Input-size guard (`CONFIG.max_input_chars`) and a global kill switch.
|
|
26
|
+
|
|
27
|
+
### Project
|
|
28
|
+
- Targets Python 3.14; ruff, mypy, and coverage run in CI; examples, contributor, and
|
|
29
|
+
security docs included.
|
|
30
|
+
|
|
31
|
+
[Unreleased]: https://github.com/pankajniet/LeanContext/compare/v2.0.0...HEAD
|
|
32
|
+
[2.0.0]: https://github.com/pankajniet/LeanContext/releases/tag/v2.0.0
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use LeanContext, please cite it."
|
|
3
|
+
title: LeanContext
|
|
4
|
+
abstract: >-
|
|
5
|
+
Deterministic, measurable context reduction for LLM agents. Trims the tool
|
|
6
|
+
output an agent re-sends to the model every turn, keeping the signal.
|
|
7
|
+
authors:
|
|
8
|
+
- family-names: Pandey
|
|
9
|
+
given-names: Pankaj
|
|
10
|
+
repository-code: "https://github.com/pankajniet/LeanContext"
|
|
11
|
+
license: Apache-2.0
|
|
12
|
+
version: 2.0.0
|
|
13
|
+
date-released: "2026-06-21"
|
|
14
|
+
keywords:
|
|
15
|
+
- llm
|
|
16
|
+
- ai-agents
|
|
17
|
+
- context-engineering
|
|
18
|
+
- tokens
|
|
19
|
+
- cost-optimization
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our community a
|
|
6
|
+
harassment-free experience for everyone, regardless of age, body size, visible or invisible
|
|
7
|
+
disability, ethnicity, sex characteristics, gender identity and expression, level of
|
|
8
|
+
experience, education, socio-economic status, nationality, personal appearance, race, religion,
|
|
9
|
+
or sexual identity and orientation.
|
|
10
|
+
|
|
11
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse,
|
|
12
|
+
inclusive, and healthy community.
|
|
13
|
+
|
|
14
|
+
## Our Standards
|
|
15
|
+
|
|
16
|
+
Examples of behavior that contributes to a positive environment:
|
|
17
|
+
|
|
18
|
+
- Showing empathy and kindness toward other people
|
|
19
|
+
- Being respectful of differing opinions, viewpoints, and experiences
|
|
20
|
+
- Giving and gracefully accepting constructive feedback
|
|
21
|
+
- Accepting responsibility and apologizing to those affected by our mistakes
|
|
22
|
+
- Focusing on what is best for the overall community
|
|
23
|
+
|
|
24
|
+
Examples of unacceptable behavior:
|
|
25
|
+
|
|
26
|
+
- The use of sexualized language or imagery, and sexual attention or advances of any kind
|
|
27
|
+
- Trolling, insulting or derogatory comments, and personal or political attacks
|
|
28
|
+
- Public or private harassment
|
|
29
|
+
- Publishing others' private information without their explicit permission
|
|
30
|
+
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
31
|
+
|
|
32
|
+
## Enforcement Responsibilities
|
|
33
|
+
|
|
34
|
+
Project maintainers are responsible for clarifying and enforcing our standards of acceptable
|
|
35
|
+
behavior and will take appropriate and fair corrective action in response to any behavior that
|
|
36
|
+
they deem inappropriate, threatening, offensive, or harmful.
|
|
37
|
+
|
|
38
|
+
## Scope
|
|
39
|
+
|
|
40
|
+
This Code of Conduct applies within all community spaces, and also applies when an individual
|
|
41
|
+
is officially representing the community in public spaces.
|
|
42
|
+
|
|
43
|
+
## Enforcement
|
|
44
|
+
|
|
45
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported privately
|
|
46
|
+
to the maintainer via a GitHub security advisory or by contacting **@pankajniet**. All
|
|
47
|
+
complaints will be reviewed and investigated promptly and fairly.
|
|
48
|
+
|
|
49
|
+
## Attribution
|
|
50
|
+
|
|
51
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1,
|
|
52
|
+
available at <https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.
|
|
53
|
+
|
|
54
|
+
[homepage]: https://www.contributor-covenant.org
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Contributing to LeanContext
|
|
2
|
+
|
|
3
|
+
Thanks for your interest. Issues and pull requests are welcome.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install -e ".[dev,otel,integrations]"
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Before you push
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
ruff check leancontext bench.py demo.py # lint
|
|
15
|
+
mypy leancontext # types
|
|
16
|
+
pytest -q # tests
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
CI runs all three on Python 3.14.
|
|
20
|
+
|
|
21
|
+
## Writing a reducer
|
|
22
|
+
|
|
23
|
+
Reducers live in `leancontext/reducers/` and are pure functions:
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
def reduce_x(text: str) -> tuple[str, list[str]]:
|
|
27
|
+
...
|
|
28
|
+
return reduced_text, notes
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
They must be:
|
|
32
|
+
|
|
33
|
+
- **Deterministic** — the same input always produces the same output (the cache and prompt
|
|
34
|
+
caching depend on this; there is a determinism test for every reducer).
|
|
35
|
+
- **Value-preserving** — never silently drop identifiers, numbers, paths, or error lines.
|
|
36
|
+
- **Anomaly-preserving** — rare and error/severity lines are the signal; keep them.
|
|
37
|
+
|
|
38
|
+
Register the reducer and its detector in `leancontext/core.py`, and add tests covering ratio,
|
|
39
|
+
determinism, and signal preservation.
|
|
40
|
+
|
|
41
|
+
## Design rules
|
|
42
|
+
|
|
43
|
+
See [AGENTS.md](AGENTS.md) for the full contract (fail-open behaviour, the no-LLM rule,
|
|
44
|
+
integration principles, and what LeanContext deliberately does not do).
|
|
45
|
+
|
|
46
|
+
## Commit messages
|
|
47
|
+
|
|
48
|
+
Plain, descriptive summaries. No AI co-author trailers.
|