contextpress 0.5.3__tar.gz → 0.5.4__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.
- {contextpress-0.5.3 → contextpress-0.5.4}/CHANGELOG.md +5 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/PKG-INFO +9 -1
- {contextpress-0.5.3 → contextpress-0.5.4}/README.md +8 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/__init__.py +1 -1
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/core.py +27 -0
- contextpress-0.5.4/examples/agent_pipeline.py +29 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/pyproject.toml +1 -1
- contextpress-0.5.4/tests/test_v054.py +53 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/.gitignore +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/CITATION.cff +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/CONTRIBUTING.md +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/LICENSE +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/NOTICE +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/_bootstrap.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/compression.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/llm/__init__.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/llm/_helpers.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/llm/adapters.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/llm/base.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/models.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/normalizer.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/pipeline.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/profiles.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/py.typed +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/registry.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/stats.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/strategies/__init__.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/strategies/base.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/strategies/budget.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/strategies/filler.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/strategies/recency.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/strategies/repetition.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/strategies/resolution.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/contextpress/warnings_capture.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/examples/benchmark_presets.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/examples/dry_run_preview.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/examples/estimate_and_stats.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/examples/llm_tier_claude.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/examples/llm_tier_gemini.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/examples/llm_tier_ollama.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/examples/llm_tier_openai.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/examples/pick_preset.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/__init__.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_budget.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_filler.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_llm_helpers.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_models.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_normalizer.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_pipeline.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_recency.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_repetition.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_resolution.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_stats.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_v03.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_v04.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_v05.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_v051.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_v052.py +0 -0
- {contextpress-0.5.3 → contextpress-0.5.4}/tests/test_v053.py +0 -0
|
@@ -4,6 +4,11 @@ All notable changes to `contextpress` are recorded here.
|
|
|
4
4
|
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [0.5.4] - 2026-07-25
|
|
8
|
+
|
|
9
|
+
- **`compress_many()`** — batch ``compress()`` over a list of conversations.
|
|
10
|
+
- Example: `examples/agent_pipeline.py` for ``type="agent"`` tool/task threads.
|
|
11
|
+
|
|
7
12
|
## [0.5.3] - 2026-07-24
|
|
8
13
|
|
|
9
14
|
- **`recommend_preset()`** — pick the mildest preset (low → medium → high) that fits a token budget.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: contextpress
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.4
|
|
4
4
|
Summary: Deterministic context compression for LLM chat, RAG, and agent pipelines
|
|
5
5
|
Project-URL: Homepage, https://github.com/Taha-azizi/contextpress
|
|
6
6
|
Project-URL: Documentation, https://github.com/Taha-azizi/contextpress#readme
|
|
@@ -323,6 +323,12 @@ preset = cm.recommend_preset(messages, token_budget=500)
|
|
|
323
323
|
out = cm.compress(messages, token_budget=500, compression=preset)
|
|
324
324
|
```
|
|
325
325
|
|
|
326
|
+
**Batch compress** (0.5.4+):
|
|
327
|
+
|
|
328
|
+
```python
|
|
329
|
+
results = cm.compress_many(list_of_conversations, token_budget=2000, return_stats=True)
|
|
330
|
+
```
|
|
331
|
+
|
|
326
332
|
**Async** (0.5+):
|
|
327
333
|
|
|
328
334
|
```python
|
|
@@ -391,6 +397,8 @@ ContextManager(type="rag_doc")
|
|
|
391
397
|
ContextManager(type="agent")
|
|
392
398
|
```
|
|
393
399
|
|
|
400
|
+
Runnable agent example: [`examples/agent_pipeline.py`](examples/agent_pipeline.py).
|
|
401
|
+
|
|
394
402
|
## Pipeline stages
|
|
395
403
|
|
|
396
404
|
1. **Filler** — Removes low-semantic filler words and (in chat/agent) drops acknowledgement-only assistant turns.
|
|
@@ -82,6 +82,12 @@ preset = cm.recommend_preset(messages, token_budget=500)
|
|
|
82
82
|
out = cm.compress(messages, token_budget=500, compression=preset)
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
+
**Batch compress** (0.5.4+):
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
results = cm.compress_many(list_of_conversations, token_budget=2000, return_stats=True)
|
|
89
|
+
```
|
|
90
|
+
|
|
85
91
|
**Async** (0.5+):
|
|
86
92
|
|
|
87
93
|
```python
|
|
@@ -150,6 +156,8 @@ ContextManager(type="rag_doc")
|
|
|
150
156
|
ContextManager(type="agent")
|
|
151
157
|
```
|
|
152
158
|
|
|
159
|
+
Runnable agent example: [`examples/agent_pipeline.py`](examples/agent_pipeline.py).
|
|
160
|
+
|
|
153
161
|
## Pipeline stages
|
|
154
162
|
|
|
155
163
|
1. **Filler** — Removes low-semantic filler words and (in chat/agent) drops acknowledgement-only assistant turns.
|
|
@@ -210,6 +210,33 @@ class ContextManager:
|
|
|
210
210
|
return CompressionResult(messages=messages_out, stats=stats)
|
|
211
211
|
return messages_out
|
|
212
212
|
|
|
213
|
+
def compress_many(
|
|
214
|
+
self,
|
|
215
|
+
conversations: list[Any],
|
|
216
|
+
token_budget: int | None = None,
|
|
217
|
+
*,
|
|
218
|
+
compression: str | None = None,
|
|
219
|
+
stages: list[str] | None = None,
|
|
220
|
+
disable: list[str] | None = None,
|
|
221
|
+
return_stats: bool = False,
|
|
222
|
+
dry_run: bool = False,
|
|
223
|
+
) -> list[Any] | list[CompressionResult]:
|
|
224
|
+
"""Run ``compress()`` on each conversation in ``conversations``."""
|
|
225
|
+
if not isinstance(conversations, list):
|
|
226
|
+
raise TypeError("conversations must be a list")
|
|
227
|
+
return [
|
|
228
|
+
self.compress(
|
|
229
|
+
messages,
|
|
230
|
+
token_budget=token_budget,
|
|
231
|
+
compression=compression,
|
|
232
|
+
stages=stages,
|
|
233
|
+
disable=disable,
|
|
234
|
+
return_stats=return_stats,
|
|
235
|
+
dry_run=dry_run,
|
|
236
|
+
)
|
|
237
|
+
for messages in conversations
|
|
238
|
+
]
|
|
239
|
+
|
|
213
240
|
async def compress_async(
|
|
214
241
|
self,
|
|
215
242
|
messages: Any,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""Agent thread compression — ``type=\"agent\"`` for tool-using pipelines."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from contextpress import ContextManager
|
|
6
|
+
|
|
7
|
+
messages = [
|
|
8
|
+
{"role": "system", "content": "You are a task agent with tools."},
|
|
9
|
+
{"role": "user", "content": "Check whether api-v2 is deployed to staging."},
|
|
10
|
+
{
|
|
11
|
+
"role": "assistant",
|
|
12
|
+
"content": "Checking deploy status <tool_call> get_deploy_status(api-v2)",
|
|
13
|
+
},
|
|
14
|
+
{"role": "user", "content": "We've decided on using the new pipeline for deploy."},
|
|
15
|
+
{"role": "assistant", "content": "Confirmed — staging deploy is scheduled."},
|
|
16
|
+
{"role": "user", "content": "What's the current status?"},
|
|
17
|
+
{"role": "assistant", "content": "Basically, honestly, " + "still rolling out " * 30},
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
cm = ContextManager(type="agent", compression="high")
|
|
21
|
+
result = cm.compress(messages, token_budget=300, return_stats=True)
|
|
22
|
+
|
|
23
|
+
print("context type:", result.stats.context_type)
|
|
24
|
+
print("turns:", result.stats.turns_before, "->", result.stats.turns_after)
|
|
25
|
+
print("tokens:", result.stats.tokens_before, "->", result.stats.tokens_after)
|
|
26
|
+
print("stages:", result.stats.stages_run)
|
|
27
|
+
for i, m in enumerate(result.messages):
|
|
28
|
+
preview = str(m.get("content", ""))[:120]
|
|
29
|
+
print(i, m["role"] + ":", preview)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
|
|
3
|
+
from contextpress import CompressionResult, ContextManager
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_compress_many_returns_list():
|
|
7
|
+
cm = ContextManager(type="chat")
|
|
8
|
+
batches = [
|
|
9
|
+
[{"role": "user", "content": "hello basically"}],
|
|
10
|
+
[{"role": "user", "content": "thanks basically"}],
|
|
11
|
+
]
|
|
12
|
+
out = cm.compress_many(batches, token_budget=200)
|
|
13
|
+
assert isinstance(out, list)
|
|
14
|
+
assert len(out) == 2
|
|
15
|
+
assert all(isinstance(item, list) for item in out)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_compress_many_with_stats():
|
|
19
|
+
cm = ContextManager(type="chat")
|
|
20
|
+
batches = [
|
|
21
|
+
[{"role": "user", "content": "hello basically there"}],
|
|
22
|
+
[{"role": "assistant", "content": "sounds good"}],
|
|
23
|
+
]
|
|
24
|
+
results = cm.compress_many(batches, token_budget=500, return_stats=True)
|
|
25
|
+
assert len(results) == 2
|
|
26
|
+
assert all(isinstance(r, CompressionResult) for r in results)
|
|
27
|
+
assert results[0].stats.turns_before == 1
|
|
28
|
+
assert results[1].stats.turns_before == 1
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_compress_many_empty():
|
|
32
|
+
cm = ContextManager(type="chat")
|
|
33
|
+
assert cm.compress_many([], token_budget=100) == []
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_compress_many_requires_list():
|
|
37
|
+
cm = ContextManager(type="chat")
|
|
38
|
+
with pytest.raises(TypeError, match="conversations must be a list"):
|
|
39
|
+
cm.compress_many("not a list") # type: ignore[arg-type]
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_agent_pipeline_compresses():
|
|
43
|
+
cm = ContextManager(type="agent", compression="high")
|
|
44
|
+
messages = [
|
|
45
|
+
{"role": "system", "content": "Agent."},
|
|
46
|
+
{"role": "user", "content": "Deploy api-v2?"},
|
|
47
|
+
{"role": "assistant", "content": "Using pipeline <tool_call> deploy"},
|
|
48
|
+
{"role": "user", "content": "We've decided on using the new pipeline for deploy."},
|
|
49
|
+
{"role": "assistant", "content": "Confirmed."},
|
|
50
|
+
]
|
|
51
|
+
result = cm.compress(messages, token_budget=200, return_stats=True)
|
|
52
|
+
assert result.stats.context_type == "agent"
|
|
53
|
+
assert result.stats.tokens_after <= result.stats.tokens_before
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|