Context¶
Auto-generated from source docstrings (mkdocstrings). The complete public contract is agentmaker.__all__ plus each subpackage __all__.
agentmaker.context: context engineering that assembles memory / RAG retrieval candidates into the model window.
memory and RAG are the "suppliers"; this subsystem does "final assembly + quality control": it picks the candidates that most deserve a place in the window, orders them, controls the budget, and compresses when they overflow. It does not re-rank (it trusts upstream retrieval to already be ordered) and only does what assembly alone can do: de-duplicate (MMR), budget per source, structure the layout, and compress as a fallback.
Provides
- mmr_select: MMR selection, relevant yet mutually distinct (reuses the vectors retrieval brings back).
- count_tokens: token estimation (mixed Chinese/English).
- ContextConfig / ContextSource: budget config (with quota validation) and the source interface.
- CallableSource: adapts any "(query) -> candidates" callable into a ContextSource.
- ContextBuilder: the main pipeline: Gather -> MMR -> three-region budget (two-round borrowing) -> skeleton assembly; build flattens everything, build_block emits only the dynamic-source block.
- HistoryCompactor: conversation history compression (cross-session Chat history: LLM summary of old turns + keep the most recent few).
- reducer: loss-aware trimming of trajectories/history (overflow protection for ReAct / Plan / Reflection trajectories, each preserving its own lifeline).
- WindowBudget / WindowBudgetConfig: window-wide accounting that allocates the whole window across output reserve / fixed overhead / retrieval block / trajectory in one place.
ContextBuilder
¶
Context assembler: assembles multi-source candidates into the final context text within budget.
__init__(config=None, *, min_chunk_tokens=None, prompts=None, token_counter=count_tokens)
¶
Build a ContextBuilder.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
Optional[ContextConfig]
|
Budget config; if omitted, the default ContextConfig is used. |
None
|
min_chunk_tokens
|
Optional[int]
|
The maximum possible tokens of a single candidate's body, used for quota sanity checking; if omitted, config.min_chunk_tokens is used (default 64). If you mainly feed RAG (chunks can reach 512), pass 512 explicitly at construction (or set it in config) for stricter checking. |
None
|
The quota is validated at construction: if a source's quota cannot hold one complete candidate block, it raises immediately (guarding against misconfiguration). Before validating, the body-measure min_chunk_tokens is augmented with the list-prefix overhead (_PREFIX_TOKENS) to convert it to the rendering measure, matching _greedy's _item_tokens at the assembly stage. This eliminates the "validate passes but assembly cannot fit" measure mismatch.
max_tokens may be omitted at construction (require_max_tokens=False): when attached to an Agent, the retrieval-block budget is supplied by the window-wide accounting WindowBudget.rag_budget via build_block(budget=...), max_tokens is not involved and may be left unset; only standalone build() / build_block(budget=None) need it, and it fails loud in those two places if missing (see _max_tokens_or_raise).
build(query, *, sources, system_prompt='', scope=None)
¶
Assemble the final context text (system -> sections -> question), flattened into one string, suitable for single-shot / RAG-style calls.
For multi-turn conversation use build_block instead: once history is flattened into a string, the user/assistant roles are lost.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
The current user question. |
required |
sources
|
List[ContextSource]
|
The various sources (memory / rag / history / ...). |
required |
system_prompt
|
str
|
The system prompt: a fixed reservation, always present, does not compete. |
''
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The assembled context text (system -> sections -> question). |
build_block(query, *, sources, scope=None, budget=None)
¶
Assemble only the dynamic-source (memory / RAG / ...) context block: no system prompt, no [Current question].
For multi-turn conversation scenarios: inject this block as a system message, while the conversation history is passed separately as role-carrying messages. Returns an empty string if there are no candidates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
query
|
str
|
The current user question (used for retrieval + budget estimation, but not written into the returned block). |
required |
sources
|
List[ContextSource]
|
The dynamic sources (memory / rag / ...). |
required |
budget
|
Optional[int]
|
An optional "retrieval-block net amount" override (from the Harness's window-wide accounting WindowBudget.rag_budget). If given: used directly as the retrieval-block budget: the window-level accounting has already deducted the output reserve and fixed overhead, so here we only further deduct the structure overhead, not re-reserve for output. If not given (None, standalone builder call): fall back to the builder's own convention max_tokens - output reserve - question - structure overhead. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
str |
str
|
The sections assembled into a context block (empty string if no candidates). |
abuild_block(query, *, sources, scope=None, budget=None)
async
¶
The async version of build_block (Harness.acontext_block uses it): the budget convention matches build_block, but multiple sources fetch concurrently via _aselect's asyncio.gather afetch (replacing serial fetch); the rest (structure overhead / MMR / allocation / joining) shares the sync implementation.
HistoryCompactor
¶
Conversation history compactor: LLM-summarize old turns + keep the most recent few turns verbatim.
__init__(llm, *, keep_recent=4, trigger_tokens=2000, max_summary_tokens=1000, summary_prompt=None, prompts=None, token_counter=count_tokens)
¶
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
llm
|
LLMClient
|
the LLM used for summarization (a cheap model such as deepseek is recommended). |
required |
keep_recent
|
int
|
how many recent turns to keep verbatim (uncompressed, ensuring the current topic stays precise and coherent). Default 4, must be >= 1. |
4
|
trigger_tokens
|
int
|
compress only when the total history token count exceeds this, otherwise return unchanged (not wasting an LLM call). Must be >= 0. |
2000
|
max_summary_tokens
|
int
|
the hard cap (in tokens) of the recap summary, truncated if exceeded. Default 1000, must be >= 1. This prevents the incrementally merged summary from growing ever larger across hundreds of turns: the LLM's merge output length is uncontrollable, and the cached summary gets fed back as input on the next turn. |
1000
|
summary_prompt
|
Optional[str]
|
the summary instruction used to compact history; if omitted, the framework default is used (central registry context.summary). Pass your own to switch language or adjust summary style. |
None
|
prompts
|
optional prompt registry (PromptRegistry, see agentmaker.prompts); if omitted, DEFAULT_PROMPTS is used. summary_prompt is a local shortcut override of it (equivalent to overriding context.summary). The recap prefix is taken from context.summary_prefix. |
None
|
from_config(llm, config, *, summary_prompt=None, prompts=None, token_counter=count_tokens)
classmethod
¶
Assemble a HistoryCompactor from an AgentmakerConfig: slice config.compaction (keep_recent / trigger_tokens).
Same mindset as each retrieval class's from_config (set defaults in one place, assemble in one line); the compactor needs the llm, so llm is passed separately.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
llm
|
LLMClient
|
the LLM used for summarization. |
required |
config
|
AgentmakerConfig (reads config.compaction). |
required | |
summary_prompt
|
Optional[str]
|
optional summary-instruction override; if omitted, the framework default is used. |
None
|
prompts
|
optional prompt registry (PromptRegistry); passed through to the constructor, and if omitted DEFAULT_PROMPTS is used (supports isolated overrides that do not pollute the global). |
None
|
compact(history, *, summarize=None)
¶
When history exceeds trigger_tokens, compress to [recap (system)] + the most recent keep_recent turns; otherwise return unchanged.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
history
|
List[Message]
|
the full conversation history. |
required |
summarize
|
optional (text, instruction) -> str summary callback (for an app's custom summary
channel). If omitted, the built-in llm is used (standalone, e.g. this file's self-test). The
Harness path goes through acompact (whose asummarize is governed via acall_llm). A summary
failure should return an empty string, and |
None
|
Returns:
| Type | Description |
|---|---|
List[Message]
|
List[Message]: the compacted history (fewer turns, fewer tokens). |
acompact(history, *, asummarize=None)
async
¶
Async version of compact: summarization goes through the asummarize callback (governed via acall_llm if Harness passes it) or the built-in llm.chat (async); splitting / assembly is shared with compact.
CallableSource
¶
Bases: ContextSource
Use a callable as a context source, with signature (query) or (query, scope) -> List[RetrievalResult].
name decides which quota it consumes (corresponding to a key of ContextConfig.source_ratios, e.g. "memory" / "rag").
scope threading (optional): whether / how the run's scope is passed to the callable is decided by
pass_scope:
- By default (pass_scope=None) it is auto-detected by positional-parameter count: if there are >= 2
positional params (e.g. lambda q, s: ...), scope is passed as the second positional argument;
a callable taking only (query) simply ignores scope.
- Warning: auto-detection only counts positional params. If your fetch takes scope as keyword-only (e.g.
def f(query, *, scope=None), as memory.search / rag.retrieve do), it will NOT be auto-recognized and
will not receive the run scope. This is intentional: bind memory.search / rag.retrieve directly and use
their own scope. To make such a fetch receive the run scope, pass pass_scope=True (passed by keyword
scope=), or rewrite it as lambda q, s: f(q, scope=s) (two positional params).
Example
CallableSource("memory", memory.search) # keyword-only scope, uses its own scope CallableSource("memory", lambda q, s: memory.search(q, scope=Scope(user=s.user))) # positional, by the run's user dimension CallableSource("rag", rag.retrieve, pass_scope=True) # explicitly pass the run scope by keyword to a keyword-only scope CallableSource("rag", lambda q: rag.retrieve(q, top_k=8)) # custom top_k, no scope
__init__(name, fetch, *, pass_scope=None)
¶
Build a CallableSource.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Source name (the quota key). |
required |
fetch
|
Callable
|
A callable that fetches candidates by query, with signature (query) or (query, scope) -> List[RetrievalResult]. |
required |
pass_scope
|
Optional[bool]
|
Whether / how to pass the run's scope to fetch. None (default) = auto-detect by
positional-parameter count (>= 2 passes scope as the second positional argument, otherwise not
passed); True = force passing by keyword |
None
|
fetch(query, scope=None)
¶
Call the underlying callable to fetch candidates (sync path). If the underlying is a coroutine (async fetch), fail loud: use afetch instead.
afetch(query, scope=None)
async
¶
Fetch candidates asynchronously: an async fetch is awaited directly, a sync fetch goes through to_thread (each source occupies its own thread when concurrent via gather).
CompactionConfig
dataclass
¶
Knobs for cross-session Chat history compression (HistoryCompactor).
Attributes:
| Name | Type | Description |
|---|---|---|
keep_recent |
int
|
How many recent items to keep as original text (not compressed, ensuring the current topic stays exact and coherent). |
trigger_tokens |
int
|
The token count the history must exceed before compression is triggered. |
validate()
¶
Range check: both must be >= 1.
ContextConfig
dataclass
¶
Context budget config (frozen and immutable; hashable, injectable, derivable via dataclasses.replace).
The budget uses "ratios" rather than absolute numbers: when you switch models (the window grows) you just scale by ratio, which is more stable than absolute numbers.
Attributes:
| Name | Type | Description |
|---|---|---|
max_tokens |
Optional[int]
|
Total budget (for the whole context). There is NO hard-coded default: it must be set from the model's real window. Prefer ContextConfig.for_window(llm.context_window), or explicitly pass a value you know to be correct. Leaving it None and building a budget anyway raises in validate(), preventing "silently use some arbitrary default". |
output_reserve_ratio |
float
|
The ratio reserved for output + the current question (does not compete for candidates). |
source_ratios |
Mapping[str, float]
|
The quota ratio of each source within the dynamic region (keys are source names, e.g. history/rag/memory/tool); the values are recommended to sum to 1, though other sums are allowed (they allocate the dynamic region by relative proportion). After construction, post_init coerces values to float and deep-freezes them read-only. |
mmr_lambda |
float
|
MMR's relevance vs diversity trade-off, passed to mmr_select. |
dedup_threshold |
float
|
MMR near-duplicate threshold (cosine >= it is treated as a duplicate and dropped; > 1 effectively disables dedup), passed to mmr_select. |
allow_borrow |
bool
|
Whether to enable quota borrowing (a source's unused idle quota is given, in a second round, to sources that still want to place more). |
min_chunk_tokens |
int
|
The token count of a single body item that a quota must at least be able to hold. |
for_window(context_window, *, use_ratio=0.5, fallback_window=None, **kwargs)
classmethod
¶
Derive the budget from the model's real context window (max_tokens = window * use_ratio) so the budget tracks the real window instead of being hard-coded.
The window comes from the llm source-of-truth (LLMClient.context_window, i.e. the vendor data verified in the profile). use_ratio defaults to 0.5: the context takes only half the window, leaving ample room for output and safety margin (a larger window need not be fully used; overly long context dilutes the signal and adds cost).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
context_window
|
Optional[int]
|
The model context window in tokens (from LLMClient.context_window). |
required |
use_ratio
|
float
|
The ratio the context takes of the window, default 0.5. |
0.5
|
fallback_window
|
Optional[int]
|
The fallback window used when the window is unknown (local / self-built models, context_window is None); it must be given explicitly (no default, forcing the caller to pin a conservative value), otherwise None raises in validate(). |
None
|
**kwargs
|
Passed through to other ContextConfig fields (source_ratios / mmr_lambda / etc.). |
{}
|
Example
ContextConfig.for_window(LLMClient("deepseek").context_window) # 1M -> max_tokens=500,000 ContextConfig.for_window(None, fallback_window=8000) # local unknown model, explicit fallback
validate(*, min_chunk_tokens=None, require_max_tokens=True)
¶
Sanity-check the config: first validate the value ranges of the numeric parameters, then ensure each source's quota can hold one complete candidate block.
Guards against two kinds of "misconfiguration": (1) a ratio / budget parameter takes an illegal value (negative reserve, out-of-range lambda, all-negative ratios, etc.), which makes the budget compute counter-intuitive results (e.g. a negative reserve inflating the context beyond the window); (2) a quota < a single candidate's size -> even the most relevant item cannot fit (except sources with an explicit ratio=0: treated as intentionally unbudgeted, this check is skipped). (Note: (2) only guards "a single item cannot fit"; "total candidates exceed the budget" is a normal trade-off, handled by the builder keeping the top few by relevance, and is not covered here.)
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
min_chunk_tokens
|
Optional[int]
|
The token count of a single item that a quota must at least hold; None (default) uses the field's own value. ContextBuilder passes in the rendering measure of "body + list prefix" to override it, aligning the check with the actual assembly footprint. |
None
|
require_max_tokens
|
bool
|
Whether to require max_tokens to have a value. True (default, the standalone builder call convention): missing max_tokens raises. False (the Agent-attached convention): the retrieval-block budget is given by the window-wide accounting WindowBudget.rag_budget, max_tokens is not involved, so a missing max_tokens is legal here and the max_tokens-related checks are skipped (including the per-source quota check, which depends on max_tokens). The structural checks (dedup / output_reserve_ratio / mmr_lambda / source_ratios) run under both conventions. |
True
|
ContextSource
¶
Bases: ABC
The unified interface for a context source: a class of supplier (memory / rag / history / ...).
name decides which quota it uses (corresponding to a key of ContextConfig.source_ratios). The system prompt is not a source: it is a fixed reservation, always present, does not compete, and is handled separately by ContextBuilder.build.
fetch(query, scope=None)
abstractmethod
¶
Fetch this source's candidates for the query (already carrying score and optional embedding).
scope: the session identifier threaded through the run (optional). Which of its dimensions to use is up to the implementation: e.g. memory uses the user dimension (user-level, cross-conversation), rag might use user/app; agentmaker only threads scope down to here and does not prescribe its semantics.
afetch(query, scope=None)
async
¶
The async version of fetch (called by ContextBuilder.abuild_block when fanning out over multiple sources via asyncio.gather).
Defaults to wrapping the sync fetch in to_thread (retrieval involves embedding / DB IO, and each source occupies its own thread concurrently); an async retrieval backend can override this to await natively.
ReducerConfig
dataclass
¶
The "how much recent original text to keep" knob for loss-aware trimming of paradigm trajectories (used by Harness.reduce).
The trajectory's token budget is not here: it is given by the window-wide accounting WindowBudget.trajectory_budget (see window_budget.py). This config only controls how many trailing steps/items of each paradigm are kept as original text without summarization.
Attributes:
| Name | Type | Description |
|---|---|---|
agent_keep_recent_steps |
int
|
How many trailing atomic units (assistant + its tool results) of the unified-loop Agent tool trajectory to keep as original text. |
plan_keep_recent |
int
|
How many trailing Plan step results to keep as original text. |
validate()
¶
Range check: keep_recent >= 0.
WindowBudget
dataclass
¶
The window budget for one run (a value object, not part of config files): allocates the whole window among competing streams.
Attributes:
| Name | Type | Description |
|---|---|---|
window |
int
|
The model's real window in tokens. |
output_reserve |
int
|
The output reserve already computed as min(three) (see WindowBudgetConfig.output_reserve). |
system_tokens |
int
|
The measured system-prompt tokens (one part of fixed overhead). |
tool_tokens |
int
|
The measured tool-schema tokens (one part of fixed overhead); they ride in the request's tools= payload, not in messages, so trajectory trimming cannot account for them. They must be subtracted separately, otherwise the unified-loop Agent's trajectory could grow large enough to push the tool schemas out of the window. |
rag_ratio |
float
|
The retrieval block's fraction of the "allocatable balance" (passed through from config). |
fixed
property
¶
Total fixed overhead = system prompt + tool schemas (convenience property).
spendable
property
¶
The balance actually divisible between retrieval block / trajectory after subtracting output reserve + fixed overhead (system + tool schemas), non-negative.
rag_budget
property
¶
Retrieval block cap = allocatable balance * rag_ratio.
trajectory_budget(*, rag_in_scope)
¶
The trimming budget for the paradigm trajectory (the two paradigm classes differ in semantics, hence the branch).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
rag_in_scope
|
bool
|
Whether the data being trimmed already contains the retrieval block. True (unified-loop Agent: the retrieval block sits as a system message in the protected head of state.messages) => gives "window - output reserve - tool schemas": the reducer counts the retrieval block / system into the head it protects, but the tool schemas hang off the tools= payload where the reducer cannot see them, so they are subtracted here separately. False (Plan/Reflection: what is trimmed is step results / draft fragments, with the retrieval block counted separately in the prompt) => gives "balance - retrieval block". |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The token budget for trajectory trimming. |
for_run(*, llm, cfg, system_tokens=0, tool_tokens=0, rag_ratio=None)
classmethod
¶
Compute one ledger from this run's real window plus the measured fixed overhead; returns None when the window is unknown (llm.context_window is None).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
llm
|
The LLM client (source of context_window and max_output_tokens). |
required | |
cfg
|
WindowBudgetConfig
|
The window allocation knobs. |
required |
system_tokens
|
int
|
The system-prompt tokens (optional; the unified-loop Agent path does not use it, see trajectory_budget). |
0
|
tool_tokens
|
int
|
The tool-schema tokens (counts tool usage into fixed overhead). |
0
|
rag_ratio
|
Optional[float]
|
Overrides cfg.rag_ratio (optional); when no retrieval source is configured, the caller passes 0 so an empty retrieval does not waste trajectory budget (without mutating the frozen cfg). |
None
|
Returns:
| Type | Description |
|---|---|
Optional[WindowBudget]
|
Optional[WindowBudget]: The ledger; None when the window is unknown (the caller |
Optional[WindowBudget]
|
then falls back to "no cap / no trimming"). |
WindowBudgetConfig
dataclass
¶
Window allocation knobs (single source-of-truth, replacing the scattered ContextConfig.output_reserve_ratio + ReducerConfig.budget_fraction).
Attributes:
| Name | Type | Description |
|---|---|---|
desired_output_tokens |
int
|
How many tokens at most you want the model to generate this time (absolute number, the main knob for the output reserve). The default is fine; raise it if you want long answers. It is further clamped by the "model hard cap" and the "window guardrail" (see output_reserve). |
max_output_fraction |
float
|
Small-window guardrail: the output reserve takes at most this fraction of the window. It only really engages on small windows (e.g. 8K), preventing the output reserve from eating up input space; on large windows it almost never triggers (clamped first by desired / model cap). |
rag_ratio |
float
|
The fraction of the "allocatable balance" that the retrieval block (memory/RAG) takes; the trajectory gets the rest. Only this one ratio is set, the trajectory no longer lists a second number, structurally ruling out "two ratios summing past the window". |
validate()
¶
Range check: output reserve >= 0, and both the guardrail and retrieval block ratio within valid ranges.
output_reserve(*, window, model_max_output)
¶
Output reserve = min(desired, model per-call hard cap, window guardrail), three clamps each guarding against one failure mode.
- desired_output_tokens: do not reserve too much (the default is already small).
- model_max_output: do not leave a dead zone on large windows: the model outputs at most this many tokens, so reserving beyond it is pure waste (None means unknown, does not participate in the clamp).
- window * max_output_fraction: do not eat up input on small windows.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
window
|
int
|
The model's real context window in tokens. |
required |
model_max_output
|
Optional[int]
|
The model's max output tokens per call (from LLMClient.max_output_tokens); None means do not clamp on it. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The token count reserved for model output this time. |
count_tokens(text)
¶
Estimate the token count of text: CJK plus Japanese/Korean characters count as 1 token each, everything else at roughly 4 characters per token.
This is a pre-send context budget estimate and does not feed billing or quota (cost and limits always use the real usage returned by the LLM). It does not tokenize on whitespace, so long whitespace-free runs (base64 / compressed data / very long URLs) are correctly covered by "other characters / 4" rather than being counted as a single token.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
text
|
str
|
The text to measure. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
int |
int
|
The estimated token count. |
mmr_select(candidates, *, top_k=None, lambda_=0.7, dedup_threshold=0.95)
¶
Select a subset from candidates by MMR: both relevant and non-redundant, dropping near-duplicates.
Two layers of de-duplication: - dedup_threshold: a candidate whose similarity to any already-selected item is >= this value is treated as a "near-duplicate" and dropped outright (actually reducing count). 0.95 means two items must be nearly byte-for-byte identical to count as duplicates; this is a "near-duplicate test", not a "relevance threshold", and is not sensitive to the exact value. - lambda_: among the non-duplicate candidates, orders by MMR balancing "relevant" against "diverse" (earlier-selected items rank higher).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
candidates
|
List[RetrievalResult]
|
Retrieval candidates (each with its own score and optional embedding; mixing candidates from different sources together enables cross-source de-dup). |
required |
top_k
|
Optional[int]
|
Maximum number to select; None = no cap on count (relies only on dedup to remove near-duplicates). |
None
|
lambda_
|
float
|
Trade-off between relevance and diversity, 0~1; 1 = purely by relevance. |
0.7
|
dedup_threshold
|
float
|
Near-duplicate removal threshold (cosine), default 0.95. |
0.95
|
Returns:
| Type | Description |
|---|---|
List[RetrievalResult]
|
List[RetrievalResult]: The selected subset, in selection order (earlier-selected first). |
reduce_agent(messages, *, summarize, budget, keep_recent_steps=3, turn_start=0, counter=count_tokens)
async
¶
Trim the unified-loop (Agent) function-call trajectory.
Protected region = all initially assembled messages (messages[:turn_start]: system + compacted conversation history + RAG blocks + current user, delimited by index rather than by "find the first user". The unified loop's trajectory contains conversation history, so the first user is an old history message and delimiting by it would summarize away the current question). The trimmable region is the tool trajectory newly added this turn afterward.
The trimmable region is sliced into atomic units (see _agent_units): the most recent keep_recent_steps units are kept verbatim, and earlier units are summarized into a single system "Attempted Steps Summary". If not over budget, returns unchanged (the same object, so the caller can tell whether trimming happened).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
messages
|
List[dict]
|
the Agent's state.messages. |
required |
summarize
|
Summarize
|
async summary callback (see module header). |
required |
budget
|
int
|
trajectory token budget (WindowBudget.trajectory_budget, includes the protected region). |
required |
keep_recent_steps
|
int
|
how many atomic units to keep at the tail, default 3. |
3
|
turn_start
|
int
|
this turn's start index (ExecutionState.meta["turn_start"], the count of initially assembled messages). |
0
|
reduce_plan(history, *, summarize, budget, keep_recent=3, counter=count_tokens)
async
¶
Trim Plan step results: keep the most recent keep_recent step results verbatim and summarize earlier ones into a single entry (preserving key numbers/conclusions).
Returns unchanged if not over budget. Each history entry looks like "Step N: ...\nResult: ...". See the module header for summarize.
reduce_reflection(entries, *, summarize, budget, counter=count_tokens)
async
¶
Trim the Reflection trajectory: keep the latest answer verbatim + summarize past critiques into a de-duplicated list of "suggestions already made", dropping superseded old drafts.
entries is a list of {"kind": "draft"|"critique"|"refine", "text": ...} (dict rather than tuple, so it passes JSON checkpoints); returns a shorter list of the same structure. The paradigm's lifeline is the "latest answer" (which it keeps refining) + the "past critique points" (to avoid re-raising suggestions already made); both are kept and old drafts are dropped. See the module header for summarize.
tokens_of(*texts, counter=count_tokens)
¶
Estimate the total token count of several texts (None treated as empty string); counter is pluggable (defaults to count_tokens).