API reference¶
Generated automatically from docstrings via mkdocstrings.
Top-level¶
convopack: framework-agnostic context-window packer for LLM chat history.
ContentBlock
module-attribute
¶
Packer ¶
Coordinates a tokenizer, a strategy, and pinning rules.
Example
from convopack import Packer, Recency packer = Packer(budget=4000, tokenizer="approx", strategy=Recency()) packed = packer.pack(messages)
Source code in src/convopack/packer.py
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | |
pack ¶
Pack a sequence of internal :class:Message objects.
Source code in src/convopack/packer.py
pack_async
async
¶
Async variant. Runs sync strategies in a thread; awaits async summarisers.
Source code in src/convopack/packer.py
pack_stream ¶
Yield :class:PackEvent items reflecting the strategy's decisions.
Useful for progress bars, audit logs, or piping pack telemetry to a
debugger. The terminal done event carries the total token count.
Source code in src/convopack/packer.py
pack_openai ¶
Convenience: accept OpenAI Chat dicts, return packed OpenAI Chat dicts.
pack_anthropic ¶
Convenience: accept Anthropic Messages dicts, return a packed payload.
Cache markers (from Packer(cache=True)) are forwarded so the
resulting payload's content blocks carry the appropriate
cache_control markers for Anthropic prompt caching.
Source code in src/convopack/packer.py
pack_gemini ¶
pack_gemini(raw: Iterable[dict[str, Any]], *, system_instruction: str | None = None) -> GeminiPayload
Convenience: accept Gemini Content dicts, return a packed payload.
Source code in src/convopack/packer.py
cache_prefix_signature ¶
Return a sha256 of the stable prefix that should drive cache hits.
For OpenAI's automatic prefix caching to work, the leading slice of
every call must be byte-identical to prior calls. This signature
covers exactly the kept messages flagged as cache-stable -- the same
ones that would receive an Anthropic cache_control marker. If the
signature differs between two calls, your cache prefix has drifted.
Source code in src/convopack/packer.py
cache_info ¶
Report what would be cached for a given history.
Returns a dict with:
markers-- indices intokeptthat get a cache marker.marked_messages-- count of those messages.marked_tokens-- tokens covered by the marked prefix.total_tokens-- tokens in the entire packed output.hit_ratio--marked_tokens / total_tokens(estimated hit ratio on the next call if the prefix doesn't drift).prefix_signature--cache_prefix_signaturefor convenience.
Source code in src/convopack/packer.py
pack_litellm ¶
Convenience: accept LiteLLM messages (OpenAI Chat shape), return packed dicts.
Source code in src/convopack/packer.py
pack_dspy ¶
Convenience: accept dspy.History or message list, return packed equivalent.
Source code in src/convopack/packer.py
pack_anthropic_managed ¶
pack_anthropic_managed(raw: Iterable[dict[str, Any]], *, system: str | None = None, trigger_tokens: int = 30000, keep_tool_uses: int = 3) -> tuple[AnthropicPayload, dict[str, Any]]
Pack AND build an Anthropic context_management config in one call.
The returned tuple is (payload, context_management_dict). Pass
the dict as the context_management argument of
client.messages.create. trigger_tokens controls when the
server compresses; keep_tool_uses is how many recent tool
exchanges survive its compression.
Source code in src/convopack/packer.py
pack_langchain ¶
Convenience: accept LangChain BaseMessage objects, return packed objects.
Drop-in replacement for langchain_core.messages.trim_messages with
the added guarantee that tool_use / tool_result pairs stay
atomic.
Source code in src/convopack/packer.py
PackResult
dataclass
¶
Result of a single pack operation.
Source code in src/convopack/_types.py
PackEvent
dataclass
¶
One step in a pack operation.
Attributes:
| Name | Type | Description |
|---|---|---|
kind |
PackEventKind
|
|
index |
int
|
Original position in the input list, or |
message |
Message | None
|
The message itself, or |
token_cost |
int
|
Tokens contributed by this message. For |
Source code in src/convopack/events.py
Message
dataclass
¶
Provider-agnostic message.
content is always a list of blocks internally. Provider adapters convert to
and from string / dict forms when crossing the public boundary.
Source code in src/convopack/_types.py
content_hash
property
¶
Stable sha256 hex digest of this message's semantic content.
The hash deliberately excludes runtime-generated tool-call IDs so that two messages with identical text, tool name, and input arguments hash the same regardless of which provider generated the wire IDs. Useful as a cache key and to detect prompt-prefix drift across packs.
TextBlock
dataclass
¶
ImageBlock
dataclass
¶
Reference to an image. source is opaque (URL, base64, file_id) and provider-specific.
Source code in src/convopack/_types.py
ToolUseBlock
dataclass
¶
Strategies¶
Packing strategies.
Strategy ¶
Bases: Protocol
A packing strategy decides which messages survive a budget cut.
Implementations must:
- keep pinned messages,
- never split a tool_use / tool_result pair,
- return a :class:
PackResultwhosekeptlist has the same relative order as the input.
Source code in src/convopack/strategies/base.py
Recency ¶
Keep the most recent chunks that still fit under budget.
Pinned messages are always kept; if pinned messages alone exceed budget,
they are still kept (the result will report fits=False).
Source code in src/convopack/strategies/recency.py
FirstFit ¶
Counterpart to :class:Recency: keep the oldest chunks that fit.
Useful when the early turns carry the load — a long system prompt, a few high-value few-shot examples, or a question whose answer needs the setup far more than the chitchat that followed.
Source code in src/convopack/strategies/firstfit.py
SummaryEvict ¶
Drop oldest chunks like :class:Recency, but replace them with a summary message.
The summariser is any callable that takes a list of messages and returns a
string (sync or async). The summary is inserted as a system message at the
head of the kept list, with the prefix [summary] to make it
identifiable.
Source code in src/convopack/strategies/summary.py
Importance ¶
Drop the lowest-scoring chunks until under budget.
A chunk's score is the maximum message score it contains, so a chunk that holds a tool_use/tool_result pair inherits the tool score.
Source code in src/convopack/strategies/importance.py
SemanticDedup ¶
Drop near-duplicate messages (by embedding similarity), then defer to a fallback strategy.
Chunks containing tool calls or pinned messages are never deduped — they're handed straight to the fallback. Among the remaining message-chunks, only the first occurrence of each near-duplicate group survives. Removing duplicates is order-preserving.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
embedder
|
Embedder
|
An object with |
required |
threshold
|
float
|
Cosine similarity above which two messages are considered duplicates. |
0.95
|
fallback
|
Strategy | None
|
Strategy to enforce the budget after dedup. Defaults to :class: |
None
|
Source code in src/convopack/strategies/dedup.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | |
Tokenizers¶
Tokenizer adapters.
Tokenizer ¶
Bases: Protocol
Counts tokens for text and messages.
Implementations should be cheap to call repeatedly. Counting a message must include any per-message overhead the target provider charges (role tags, separators, tool framing).
Source code in src/convopack/tokenizers/base.py
ApproxTokenizer ¶
Estimates tokens as ceil(char_count / 4).
Use when you don't want to pull in tiktoken or anthropic. Numbers will be off by 10-30% depending on language; fine for a soft budget but not for billing.
Source code in src/convopack/tokenizers/approx.py
get_tokenizer ¶
Resolve a tokenizer from a string spec or pass through an instance.
Spec formats:
- "tiktoken:<encoding-or-model>" -- e.g. "tiktoken:gpt-4o".
- "anthropic:<model>" -- e.g. "anthropic:claude-sonnet-4-6".
- "huggingface:<model-id>" -- any HuggingFace tokenizer id.
- "approx" -- char-length / 4 estimator (zero deps).
Source code in src/convopack/tokenizers/__init__.py
tiktoken-backed tokenizer (OpenAI BPE).
TiktokenAdapter ¶
Wraps a tiktoken encoding. Specify either a model name or an encoding name.
Source code in src/convopack/tokenizers/tiktoken_adapter.py
Anthropic tokenizer adapter.
Anthropic does not ship a local tokenizer; the official method is to call
messages.count_tokens on the server. That is a network call, so we offer
two modes:
offline=True(default) -- delegate to :class:ApproxTokenizer. Fast and free, off by ~10-15%.offline=False-- if theanthropicSDK is installed and an API key is configured, callclient.messages.count_tokensfor exact counts. Slow.
HuggingFace transformers-backed tokenizer adapter.
HFTokenizerAdapter ¶
Wraps a HuggingFace AutoTokenizer so any open-weights model can be used.
Pass either a HuggingFace model id (e.g. meta-llama/Llama-3.1-8B) or a
local path. Tokeniser files are downloaded on first use unless
local_files_only=True.
Source code in src/convopack/tokenizers/huggingface_adapter.py
Embedders¶
Embedder protocol for semantic strategies.
Embedder ¶
Bases: Protocol
Turns text into a dense vector.
Implementations may optionally provide :meth:embed_batch for efficiency;
a default implementation that loops over embed is acceptable.
Source code in src/convopack/embedders/base.py
cosine ¶
Cosine similarity. Returns 0 if either vector is zero.
Source code in src/convopack/embedders/base.py
Providers¶
Provider message-shape adapters.
GeminiPayload
dataclass
¶
from_openai ¶
Convert OpenAI Chat Completions messages into :class:Message objects.
Source code in src/convopack/providers/openai.py
to_openai ¶
Convert :class:Message objects into OpenAI Chat Completions shape.
Source code in src/convopack/providers/openai.py
from_anthropic ¶
Convert Anthropic-shape messages (and optional system prompt) to internal form.
Source code in src/convopack/providers/anthropic.py
to_anthropic ¶
to_anthropic(messages: Iterable[Message], *, cache_markers: list[int] | None = None) -> AnthropicPayload
Convert internal messages to an :class:AnthropicPayload.
System messages are concatenated into a single system string. The
remaining messages are emitted in Anthropic content-block shape.
If cache_markers is provided, it is interpreted as indices into the
input messages list; the last content block of each marked
message receives {"cache_control": {"type": "ephemeral"}}. Markers
pointing at system messages are attached to the system string fragment
instead, since Anthropic's system field is just a list of text blocks
under the hood.
Source code in src/convopack/providers/anthropic.py
from_gemini ¶
from_gemini(contents: Iterable[dict[str, Any]], system_instruction: str | None = None) -> list[Message]
Convert Gemini Content dicts (and optional system instruction).
Source code in src/convopack/providers/gemini.py
to_gemini ¶
Convert internal messages to a :class:GeminiPayload.
System messages are concatenated into system_instruction. Tool calls
become function_call parts; tool results become function_response
parts on a synthetic user turn. Internal tool_use_id values are
stripped because Gemini does not carry them.