LLMSlim + gptme
A gptme context provider for automatic compaction and /compact trim. Older tool output is compressed instead of being replaced by a stub.
LLMSlimContextProvider is a gptme context provider backed by LLMSlim. It keeps the system prompt, the first messages, pinned messages, tool calls and the latest turns exactly as they are, and compresses older tool output and history until the conversation fits gptme's limit. Tool output keeps its failures, tracebacks and line structure. It runs locally, with no model call. Python 3.10+.
1. Installation and setup
The extra installs gptme 0.34 or newer and needs Python 3.10 or newer. Installing llmslim registers two gptme entry points, so there is nothing to import or register yourself. gptme pins mcp<2, while llmslim[mcp] and llmslim[agents] need mcp>=2, so they cannot share an environment; that is also why llmslim[all] does not include gptme.
pip install "llmslim[gptme]" # gptme 0.34 or newer, Python 3.10+; needs llmslim 0.9.0 or newerTo make LLMSlim the provider gptme's own compaction uses, turn it on in ~/.config/gptme/config.toml (or in a project's gptme.toml, which overrides the user file key by key):
[plugin.llmslim]
compaction = true
# Optional:
keep_recent = 6 # most recent messages kept verbatim (tool output in them is still capped)
min_tokens = 200 # shorter messages are never compressed2. Architecture & execution flow
3. Runnable example and its output
from gptme.message import Message
from gptme.tools.autocompact.context_provider import CompressionConfig, get_context_provider
from llmslim import count_tokens
# 300 lines of test output with one failure, as gptme's shell tool would return it.
lines = [f"tests/test_api.py::test_case_{i} PASSED" for i in range(300)]
lines.insert(200, "tests/test_refund.py::test_rounding FAILED - AssertionError: 10.05 != 10.04")
test_output = "Ran command: `pytest -q`\n" + "\n".join(lines)
log = [
Message("system", "You are gptme, a coding agent.", pinned=True),
Message("user", "Fix the failing refund test."),
Message("assistant", "Running the tests.\n```shell\npytest -q\n```"),
Message("system", test_output),
Message("assistant", "One test fails: test_rounding. Reading refund.py next."),
Message("user", "Go ahead."),
]
provider = get_context_provider("llmslim") # found through llmslim's entry point
result = provider.compress(log, CompressionConfig(limit=1000, keep_head=2))
for before, after in zip(log, result.messages):
print(f"{before.role:9} {count_tokens(before.content):5} -> {count_tokens(after.content):4} tokens")
print(result.limitations[0])
print()
print(result.messages[3].content)Output (Python 3.12, gptme 0.34.0, token counts from tiktoken):
system 10 -> 10 tokens
user 6 -> 6 tokens
assistant 12 -> 12 tokens
system 3631 -> 91 tokens
assistant 13 -> 13 tokens
user 3 -> 3 tokens
LLMSlim extractive compression: 3,675 -> 135 tokens; budget 1,000; 1 compressed, 0 dropped
Ran command: `pytest -q`
tests/test_api.py::test_case_0 PASSED
... [198 similar lines]
tests/test_api.py::test_case_199 PASSED
tests/test_refund.py::test_rounding FAILED - AssertionError: 10.05 != 10.04
tests/test_api.py::test_case_200 PASSED
... [98 similar lines]
tests/test_api.py::test_case_299 PASSEDgptme stores tool output as system messages. The test output is over gptme's 2,000-token limit for a single tool result, so it is compressed even though it is recent: the failure and its neighbours stay, and the runs of passing tests collapse into a count. This output is a favourable case, because near-identical lines compress very well; prose is compressed only as far as the budget requires. The tool call that produced the output is kept as it is, so the model still sees which command ran.
4. Options
Keyword arguments, shown as name = default.