Context reduction¶
Fit a document corpus to a token budget. Your application collects; this subpackage reduces. The reasoning and the strategy tradeoffs are in context reduction; the task-oriented walkthrough is fitting a corpus to a budget.
Imported from its own path, like the other optional subsystems:
from anyinfer import context
Documents and results¶
anyinfer.context.ContextDocument
dataclass
¶
ContextDocument(
path: str,
content: str,
sha256: str,
pinned: bool = False,
language: str | None = None,
extract: str = "",
)
One document offered to the reducer.
Attributes:
| Name | Type | Description |
|---|---|---|
path |
str
|
POSIX-style relative path. Doubles as identity and as a ranking signal — a query term matching the path outweighs the same term in the body. |
content |
str
|
The document's text. |
sha256 |
str
|
Hex digest of |
pinned |
bool
|
Sorts before every unpinned document and is selected first. This is how an app says "the user explicitly chose this file". |
language |
str | None
|
Language name for rendering and rollups, detected when omitted. |
extract |
str
|
A structural summary (signatures, imports, headings) used by the
|
of
classmethod
¶
of(
path: str,
content: str,
*,
pinned: bool = False,
language: str | None = None,
extract: str | None = None,
) -> ContextDocument
Build a document, computing its digest and filling in what was omitted.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
path
|
str
|
POSIX-style relative path. |
required |
content
|
str
|
The document's text. |
required |
pinned
|
bool
|
Whether the document must be included ahead of ranked candidates. |
False
|
language
|
str | None
|
Overrides language detection. |
None
|
extract
|
str | None
|
Overrides extraction. Pass |
None
|
Returns:
| Type | Description |
|---|---|
ContextDocument
|
The document, with |
ContextDocument
|
they were supplied. |
anyinfer.context.Reduction
dataclass
¶
Reduction(
strategy: str,
representation: str,
documents: tuple[ContextDocument, ...],
candidate_count: int,
text: str,
estimated_tokens: int,
max_tokens: int,
max_bytes: int,
max_documents: int,
total_bytes: int,
binding_constraints: tuple[str, ...] = (),
tier_metadata: Mapping[str, Any] | None = None,
)
What a reduction produced, and what it cost.
Attributes:
| Name | Type | Description |
|---|---|---|
strategy |
str
|
The strategy that was requested. |
representation |
str
|
The strategy actually applied — what |
documents |
tuple[ContextDocument, ...]
|
Documents represented at full or extract fidelity. In |
candidate_count |
int
|
How many documents were offered. |
text |
str
|
The rendered envelope. Always present — place it in your own message. |
estimated_tokens |
int
|
Planning-side estimate of |
max_tokens |
int
|
The token budget this reduction was held to. |
max_bytes |
int
|
The byte ceiling in force. |
max_documents |
int
|
The document-count ceiling in force. |
total_bytes |
int
|
UTF-8 byte length of |
binding_constraints |
tuple[str, ...]
|
Which ceilings excluded at least one document, in the fixed
order |
tier_metadata |
Mapping[str, Any] | None
|
Strategy-specific detail (tier composition, chunk counts). |
omitted_count
property
¶
omitted_count: int
How many offered documents are not represented in detail.
complete
property
¶
complete: bool
Whether every offered document was represented without any ceiling binding.
metadata ¶
metadata() -> dict[str, Any]
The full machine-readable record, for logging or a debug pane.
summary ¶
summary() -> str
A one-line, content-free description of what happened.
Safe to show a user or write to a log: counts and ceilings only, never paths or content — a path name can itself be sensitive.
event ¶
event(*, calls: int = 0) -> ContextReduced
Build the telemetry event describing this reduction.
anyinfer.context.Strategy
module-attribute
¶
Strategy = Literal[
"auto", "whole", "ranked", "tiered", "packed"
]
Names accepted by select's strategy argument.
anyinfer.context.RenderOrder
module-attribute
¶
RenderOrder = Literal['path', 'rank']
Whether selected documents render by stable path order or relevance rank.
anyinfer.context.RankCache
dataclass
¶
RankCache(
term_counts: dict[str, Counter[str]] = dict(),
document_frequency: Counter[str] = Counter(),
document_lengths: dict[str, int] = dict(),
total_documents: int = 0,
)
Precomputed term statistics for one corpus.
Ranking a corpus repeatedly — as an interactive app does on every turn — otherwise
re-tokenizes every document each time. Build one with
anyinfer.context.rank.build_rank_cache() and pass it back in.
Validity is the caller's responsibility: key it on a corpus hash and rebuild when the corpus changes. Passing a cache built from different documents produces undefined ranking rather than an error, which is why the cache is not consulted for document identity.
Attributes:
| Name | Type | Description |
|---|---|---|
term_counts |
dict[str, Counter[str]]
|
Per-document term frequencies, keyed by document path. |
document_frequency |
Counter[str]
|
How many documents contain each term. |
document_lengths |
dict[str, int]
|
Total token count per document, for length normalization. |
total_documents |
int
|
Corpus size, for the inverse-document-frequency term. |
Selection¶
anyinfer.context.select ¶
Corpus selection: the strategies, the result type, and the dispatch rule.
Reduction is emulation of a larger context window, and emulation announces itself. Every
reduction returns what it kept, what it dropped, which ceiling bound it, and a
content-free summary — plus a ContextReduced telemetry event when an observer is
supplied. A silent truncation that looks like a complete answer is the failure mode this
module exists to prevent.
DEFAULT_MAX_DOCUMENTS
module-attribute
¶
DEFAULT_MAX_DOCUMENTS = 200
Ceiling on documents in one envelope; a long tail of tiny files helps nobody.
DEFAULT_MAX_BYTES
module-attribute
¶
DEFAULT_MAX_BYTES = 4 * 1024 * 1024
Byte ceiling, enforced independently of tokens because transports cap bytes.
VALID_STRATEGIES
module-attribute
¶
VALID_STRATEGIES = (
"auto",
"whole",
"ranked",
"tiered",
"packed",
)
Strategy names select() accepts.
Strategy
module-attribute
¶
Strategy = Literal[
"auto", "whole", "ranked", "tiered", "packed"
]
Names accepted by select's strategy argument.
RenderOrder
module-attribute
¶
RenderOrder = Literal['path', 'rank']
Whether selected documents render by stable path order or relevance rank.
Reduction
dataclass
¶
Reduction(
strategy: str,
representation: str,
documents: tuple[ContextDocument, ...],
candidate_count: int,
text: str,
estimated_tokens: int,
max_tokens: int,
max_bytes: int,
max_documents: int,
total_bytes: int,
binding_constraints: tuple[str, ...] = (),
tier_metadata: Mapping[str, Any] | None = None,
)
What a reduction produced, and what it cost.
Attributes:
| Name | Type | Description |
|---|---|---|
strategy |
str
|
The strategy that was requested. |
representation |
str
|
The strategy actually applied — what |
documents |
tuple[ContextDocument, ...]
|
Documents represented at full or extract fidelity. In |
candidate_count |
int
|
How many documents were offered. |
text |
str
|
The rendered envelope. Always present — place it in your own message. |
estimated_tokens |
int
|
Planning-side estimate of |
max_tokens |
int
|
The token budget this reduction was held to. |
max_bytes |
int
|
The byte ceiling in force. |
max_documents |
int
|
The document-count ceiling in force. |
total_bytes |
int
|
UTF-8 byte length of |
binding_constraints |
tuple[str, ...]
|
Which ceilings excluded at least one document, in the fixed
order |
tier_metadata |
Mapping[str, Any] | None
|
Strategy-specific detail (tier composition, chunk counts). |
omitted_count
property
¶
omitted_count: int
How many offered documents are not represented in detail.
complete
property
¶
complete: bool
Whether every offered document was represented without any ceiling binding.
metadata ¶
metadata() -> dict[str, Any]
The full machine-readable record, for logging or a debug pane.
summary ¶
summary() -> str
A one-line, content-free description of what happened.
Safe to show a user or write to a log: counts and ceilings only, never paths or content — a path name can itself be sensitive.
event ¶
event(*, calls: int = 0) -> ContextReduced
Build the telemetry event describing this reduction.
normalize_strategy ¶
normalize_strategy(value: str | None) -> str
Normalize a strategy name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str | None
|
The requested strategy; |
required |
Returns:
| Type | Description |
|---|---|
str
|
The lowercase strategy name. |
Raises:
| Type | Description |
|---|---|
ValueError
|
On an unrecognized strategy, listing the valid names. |
select ¶
select(
documents: Iterable[ContextDocument],
query: str,
*,
max_tokens: int,
strategy: str = "auto",
max_documents: int = DEFAULT_MAX_DOCUMENTS,
max_bytes: int = DEFAULT_MAX_BYTES,
estimator: TokenEstimator | None = None,
rank_cache: RankCache | None = None,
module_digests: Mapping[str, str] | None = None,
render_order: RenderOrder = "path",
observer: Observer | None = None,
) -> Reduction
Reduce a corpus to fit a token budget.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
documents
|
Iterable[ContextDocument]
|
The corpus the app has already collected and approved. |
required |
query
|
str
|
What the request is about, used for relevance ranking. |
required |
max_tokens
|
int
|
The token budget. Normally
|
required |
strategy
|
str
|
|
'auto'
|
max_documents
|
int
|
Ceiling on documents represented. |
DEFAULT_MAX_DOCUMENTS
|
max_bytes
|
int
|
Ceiling on envelope bytes. |
DEFAULT_MAX_BYTES
|
estimator
|
TokenEstimator | None
|
Token counting strategy; defaults to the byte heuristic. |
None
|
rank_cache
|
RankCache | None
|
Precomputed corpus statistics, for repeated queries. |
None
|
module_digests
|
Mapping[str, str] | None
|
App-supplied per-module summaries, rendered by |
None
|
render_order
|
RenderOrder
|
|
'path'
|
observer
|
Observer | None
|
Receives a |
None
|
Returns:
| Type | Description |
|---|---|
Reduction
|
The |
Raises:
| Type | Description |
|---|---|
ValueError
|
On an unknown strategy or a non-positive budget. |
anyinfer.context.normalize_strategy ¶
normalize_strategy(value: str | None) -> str
Normalize a strategy name.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
value
|
str | None
|
The requested strategy; |
required |
Returns:
| Type | Description |
|---|---|
str
|
The lowercase strategy name. |
Raises:
| Type | Description |
|---|---|
ValueError
|
On an unrecognized strategy, listing the valid names. |
anyinfer.context.VALID_STRATEGIES
module-attribute
¶
VALID_STRATEGIES = (
"auto",
"whole",
"ranked",
"tiered",
"packed",
)
Strategy names select() accepts.
anyinfer.context.DEFAULT_MAX_DOCUMENTS
module-attribute
¶
DEFAULT_MAX_DOCUMENTS = 200
Ceiling on documents in one envelope; a long tail of tiny files helps nobody.
anyinfer.context.DEFAULT_MAX_BYTES
module-attribute
¶
DEFAULT_MAX_BYTES = 4 * 1024 * 1024
Byte ceiling, enforced independently of tokens because transports cap bytes.
Ranking¶
Public so it can be replaced: the shipped ranker is lexical, and an application needing semantic retrieval ranks its own documents and passes the result through.
anyinfer.context.rank ¶
Lexical relevance ranking.
A BM25-style scorer, deliberately lexical and dependency-free: term frequency saturated and length-normalized, weighted by inverse document frequency, plus two signals that matter a great deal in a code or document corpus and nothing in classical IR — a path match outweighs a body match, and well-known anchor files (README, pyproject.toml, ARCHITECTURE) get a small bonus.
What this is not. There are no embeddings and no semantic matching: a query for "authentication" will not find a file that only says "login". That is a deliberate boundary — see the concept documentation — and the reason ranking is exposed as a function you can replace rather than hidden inside selection.
Tokenization is ASCII alphanumeric. Ranking is fully deterministic: ties break on path depth, then path, then digest, so the same corpus and query always produce the same order regardless of the order documents were supplied in.
STOP_WORDS
module-attribute
¶
STOP_WORDS = frozenset(
{
"a",
"about",
"all",
"an",
"and",
"any",
"are",
"as",
"at",
"be",
"been",
"but",
"by",
"can",
"do",
"does",
"for",
"from",
"get",
"has",
"have",
"how",
"i",
"if",
"in",
"into",
"is",
"it",
"its",
"of",
"on",
"or",
"please",
"should",
"so",
"some",
"than",
"that",
"the",
"their",
"them",
"then",
"there",
"these",
"this",
"to",
"use",
"was",
"were",
"what",
"when",
"where",
"which",
"who",
"why",
"will",
"with",
"would",
"you",
"your",
}
)
Words carrying no retrieval signal, dropped from queries and documents alike.
TERM_SATURATION
module-attribute
¶
TERM_SATURATION = 1.2
BM25's k1: how fast repeated occurrences of a term stop adding score.
LENGTH_NORMALIZATION
module-attribute
¶
LENGTH_NORMALIZATION = 0.001
Penalty per token of document length, so a long file cannot win on volume alone.
PATH_MATCH_WEIGHT
module-attribute
¶
PATH_MATCH_WEIGHT = 4.0
How much more a query term in the path counts than the same term in the body.
Deliberately large: someone asking about credentials almost always means the file
named for it, even when a dozen other files mention the word more often.
ANCHOR_SCORE
module-attribute
¶
ANCHOR_SCORE = 0.25
Bonus for files that orient a reader regardless of the query.
ANCHOR_NAMES
module-attribute
¶
ANCHOR_NAMES = frozenset(
{
"architecture",
"changelog",
"contributing",
"design",
"overview",
"readme",
"cargo.toml",
"go.mod",
"package.json",
"pom.xml",
"pyproject.toml",
}
)
Filenames (and stems) worth a small unconditional boost.
tokenize ¶
tokenize(text: str) -> list[str]
Split text into lowercase alphanumeric terms, dropping stop words.
ASCII-only by design — the tradeoff is stated in the module documentation.
build_rank_cache ¶
build_rank_cache(
documents: Iterable[ContextDocument],
) -> RankCache
Precompute term statistics for a corpus.
Pass the result to rank() on subsequent queries over the same corpus. The caller
owns invalidation; see RankCache.
score_document ¶
score_document(
document: ContextDocument,
query_terms: Counter[str],
cache: RankCache,
) -> float
Score one document against a query.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document
|
ContextDocument
|
The candidate. |
required |
query_terms
|
Counter[str]
|
Query term frequencies, from |
required |
cache
|
RankCache
|
Corpus statistics covering this document. |
required |
Returns:
| Type | Description |
|---|---|
float
|
A non-negative relevance score. Zero means nothing matched — which is still a |
float
|
valid candidate, just an unranked one. |
rank ¶
rank(
documents: Sequence[ContextDocument],
query: str,
*,
rank_cache: RankCache | None = None,
) -> list[ContextDocument]
Order documents by relevance, pinned ones first.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
documents
|
Sequence[ContextDocument]
|
The corpus. |
required |
query
|
str
|
What the app is asking about. An empty query ranks everything at zero, leaving the deterministic tie-break as the order. |
required |
rank_cache
|
RankCache | None
|
Precomputed statistics for this corpus; built on the fly when absent. |
None
|
Returns:
| Type | Description |
|---|---|
list[ContextDocument]
|
A new list, most relevant first. Ordering is total and deterministic: every |
list[ContextDocument]
|
pinned document precedes every unpinned one, then higher score, then shallower |
list[ContextDocument]
|
path, then path, then digest. |
anyinfer.context.build_rank_cache ¶
build_rank_cache(
documents: Iterable[ContextDocument],
) -> RankCache
Precompute term statistics for a corpus.
Pass the result to rank() on subsequent queries over the same corpus. The caller
owns invalidation; see RankCache.
anyinfer.context.tokenize ¶
tokenize(text: str) -> list[str]
Split text into lowercase alphanumeric terms, dropping stop words.
ASCII-only by design — the tradeoff is stated in the module documentation.
Structure and tiers¶
anyinfer.context.detect_language ¶
detect_language(path: str) -> str | None
Infer a language from a path's suffix, or None when it is ambiguous.
anyinfer.context.structural_extract ¶
structural_extract(
content: str, *, language: str | None
) -> str
Reduce a document to its declarations, imports, and headings.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
str
|
The document text. |
required |
language
|
str | None
|
The detected language. |
required |
Returns:
| Type | Description |
|---|---|
str
|
The extract, or |
str
|
|
str
|
summary. |
anyinfer.context.is_generated_path ¶
is_generated_path(path: str) -> bool
Whether a path looks machine-generated or vendored.
Offered as a public helper because the decision belongs at collection time — the library never walks a filesystem, but an app deciding what to collect needs the same heuristic AnyInfer would have applied.
anyinfer.context.module_surfaces ¶
module_surfaces(
documents: Sequence[ContextDocument], *, depth: int = 2
) -> dict[str, str]
Group a corpus into modules and render each one's surface text.
Offered as a public helper for the app-side digest recipe: generate a summary per
module with your own client, cache it keyed on the surface's digest, and hand the
results back as module_digests. Deterministic, so the cache key is stable.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
documents
|
Sequence[ContextDocument]
|
The corpus. |
required |
depth
|
int
|
Path-prefix depth at which to group. |
2
|
Returns:
| Type | Description |
|---|---|
dict[str, str]
|
Module path to concatenated extract (or content) text, in path order. |
anyinfer.context.DEFAULT_ROLLUP_SHARE
module-attribute
¶
DEFAULT_ROLLUP_SHARE = 0.45
Share of the token and byte budget reserved for the module rollup.
Chunking¶
anyinfer.context.Chunk
dataclass
¶
Chunk(
document: ContextDocument,
text: str,
index: int,
start_line: int,
end_line: int,
)
One span of a document.
Attributes:
| Name | Type | Description |
|---|---|---|
document |
ContextDocument
|
The document this came from. |
text |
str
|
The span's text. |
index |
int
|
Position within the document, from zero. |
start_line |
int
|
First line of the span, 1-based and inclusive. |
end_line |
int
|
Last line of the span, 1-based and inclusive. |
anyinfer.context.split_document ¶
split_document(
document: ContextDocument,
*,
chunk_tokens: int = DEFAULT_CHUNK_TOKENS,
) -> list[Chunk]
Split a document into boundary-aware chunks with line spans.
Prefers the last blank line within budget, falls back to the last line break, and hard-cuts only when neither lands past a quarter of the budget.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
document
|
ContextDocument
|
The document to split. |
required |
chunk_tokens
|
int
|
Target chunk size in planning tokens. |
DEFAULT_CHUNK_TOKENS
|
Returns:
| Type | Description |
|---|---|
list[Chunk]
|
Chunks in document order. A document shorter than one chunk yields exactly one. |
anyinfer.context.DEFAULT_CHUNK_TOKENS
module-attribute
¶
DEFAULT_CHUNK_TOKENS = 512
Target chunk size. Large enough for a whole function, small enough to pack several.
Distillation¶
The only reduction that spends inference. See distill a corpus for the cookbook.
anyinfer.context.distill ¶
The distill strategy: map/reduce a corpus that will never fit.
The other strategies decide what to drop. This one reads everything and writes something shorter: each chunk is summarized against the query (the map phase), then the notes are synthesized into one answer (the reduce phase).
It is separated from anyinfer.context.select by construction, because it is the one
strategy that spends money. It takes your client, issues real generation calls, and
reports the count and aggregate usage so the multiplier is never a surprise.
Two properties distinguish this from a naive map/reduce. Reduction is hierarchical: if the map notes together exceed the target's window, they are reduced in batches and the batch summaries reduced again, rather than being sent in one overflowing request. And a deterministic reducer can replace the reduce call entirely, so an application that merges structurally pays for the map phase only.
Prompts here are mechanical scaffolding — "here is chunk 3 of 9, take notes" — not
application prose. You own the question; override map_instructions and
reduce_instructions to own the framing too.
DEFAULT_CONCURRENCY
module-attribute
¶
DEFAULT_CONCURRENCY = 4
Map calls in flight at once. Bounded because a fan-out is someone's rate limit.
SupportsGenerate ¶
Bases: Protocol
The slice of an async client distill() needs.
A structural protocol rather than an import, so this subpackage never depends on the
client — anyinfer.AsyncClient satisfies it as-is.
SupportsGenerateSync ¶
Bases: Protocol
The synchronous mirror of SupportsGenerate, satisfied by anyinfer.Client.
Distillation
dataclass
¶
Distillation(
text: str,
chunk_count: int,
calls: int,
usage: Usage,
reduce_depth: int = 1,
notes: tuple[str, ...] = (),
)
What a distillation produced, and what it cost.
Attributes:
| Name | Type | Description |
|---|---|---|
text |
str
|
The synthesized answer. |
chunk_count |
int
|
How many chunks the source was split into. |
calls |
int
|
Total generation calls spent, map and reduce together. This is the multiplier over a single request. |
usage |
Usage
|
Merged usage across every call, including cost when providers report it. |
reduce_depth |
int
|
1 for a single-pass reduce; higher when notes were reduced in batches and the batch summaries reduced again. |
notes |
tuple[str, ...]
|
The intermediate map outputs. Payload-bearing — excluded from |
distill
async
¶
distill(
source: str | Iterable[ContextDocument],
query: str,
*,
client: SupportsGenerate,
target: str,
max_output_tokens: int = 1024,
chunk_tokens: int | None = None,
concurrency: int = DEFAULT_CONCURRENCY,
map_instructions: str | None = None,
reduce_instructions: str | None = None,
reducer: Callable[[Sequence[str]], str] | None = None,
observer: Observer | None = None,
) -> Distillation
Summarize a corpus larger than the window by mapping and reducing over it.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
str | Iterable[ContextDocument]
|
Raw text, or documents. Documents split per document, because a document boundary is a natural chunk boundary. |
required |
query
|
str
|
What the summary should answer. |
required |
client
|
SupportsGenerate
|
Anything satisfying |
required |
target
|
str
|
Where to send the calls. |
required |
max_output_tokens
|
int
|
Ceiling on the final answer. |
1024
|
chunk_tokens
|
int | None
|
Chunk size. Derived from the target's remaining budget when omitted. |
None
|
concurrency
|
int
|
Map calls in flight at once. |
DEFAULT_CONCURRENCY
|
map_instructions
|
str | None
|
Replaces the default note-taking instruction. |
None
|
reduce_instructions
|
str | None
|
Replaces the default synthesis instruction. |
None
|
reducer
|
Callable[[Sequence[str]], str] | None
|
Merge the notes deterministically instead of with a reduce call. Saves every reduce call, and makes the merge reproducible. |
None
|
observer
|
Observer | None
|
Receives a |
None
|
Returns:
| Type | Description |
|---|---|
Distillation
|
The |
Raises:
| Type | Description |
|---|---|
ConfigError
|
When |
distill_sync ¶
distill_sync(
source: str | Iterable[ContextDocument],
query: str,
*,
client: SupportsGenerateSync,
target: str,
max_output_tokens: int = 1024,
chunk_tokens: int | None = None,
map_instructions: str | None = None,
reduce_instructions: str | None = None,
reducer: Callable[[Sequence[str]], str] | None = None,
observer: Observer | None = None,
) -> Distillation
Run distill() sequentially against a synchronous client.
Chunks are processed one at a time: concurrency is the async path's feature, and a
sync caller that wants it should use distill() with an anyinfer.AsyncClient.
Args and returns are as distill(), minus concurrency.
Raises:
| Type | Description |
|---|---|
ConfigError
|
When |
anyinfer.context.distill_sync ¶
distill_sync(
source: str | Iterable[ContextDocument],
query: str,
*,
client: SupportsGenerateSync,
target: str,
max_output_tokens: int = 1024,
chunk_tokens: int | None = None,
map_instructions: str | None = None,
reduce_instructions: str | None = None,
reducer: Callable[[Sequence[str]], str] | None = None,
observer: Observer | None = None,
) -> Distillation
Run distill() sequentially against a synchronous client.
Chunks are processed one at a time: concurrency is the async path's feature, and a
sync caller that wants it should use distill() with an anyinfer.AsyncClient.
Args and returns are as distill(), minus concurrency.
Raises:
| Type | Description |
|---|---|
ConfigError
|
When |
anyinfer.context.Distillation
dataclass
¶
Distillation(
text: str,
chunk_count: int,
calls: int,
usage: Usage,
reduce_depth: int = 1,
notes: tuple[str, ...] = (),
)
What a distillation produced, and what it cost.
Attributes:
| Name | Type | Description |
|---|---|---|
text |
str
|
The synthesized answer. |
chunk_count |
int
|
How many chunks the source was split into. |
calls |
int
|
Total generation calls spent, map and reduce together. This is the multiplier over a single request. |
usage |
Usage
|
Merged usage across every call, including cost when providers report it. |
reduce_depth |
int
|
1 for a single-pass reduce; higher when notes were reduced in batches and the batch summaries reduced again. |
notes |
tuple[str, ...]
|
The intermediate map outputs. Payload-bearing — excluded from |
anyinfer.context.SupportsGenerate ¶
Bases: Protocol
The slice of an async client distill() needs.
A structural protocol rather than an import, so this subpackage never depends on the
client — anyinfer.AsyncClient satisfies it as-is.
Rendering¶
The envelope format, exposed for applications that parse reduced context back out of stored transcripts.
anyinfer.context.render_corpus ¶
render_corpus(blocks: Iterable[str]) -> str
Wrap rendered blocks in the corpus element.
anyinfer.context.render_file_block ¶
render_file_block(document: ContextDocument) -> str
Render a whole document.
anyinfer.context.render_extract_block ¶
render_extract_block(document: ContextDocument) -> str
Render a document's structural extract.
anyinfer.context.render_chunk_block ¶
render_chunk_block(
document: ContextDocument,
text: str,
start_line: int,
end_line: int,
) -> str
Render one contiguous span of a document, with its line range.