Start with observation
Add a policy to your existing agent definition:agent.py
instructions.md. TokenPolicy() observes without changing the model request or blocking calls. Harnest logs numeric reports at INFO level through harnest.tokens, or sends them to your observer callback. It does not log prompt or tool-result content through this feature.
You can set budgets while leaving enforce=False to observe which input, context-window, and model-call budgets would be exceeded. An output limit is passed to the provider only when enforcement is enabled.
Choose limits and reductions
Agent(token_policy=policy, ...). These numbers are examples, not defaults. Configure each graph agent or subagent independently; a parent’s policy does not automatically configure its children or native targets.
Reductions run when you explicitly configure them, even if
enforce=False. To observe unchanged requests, leave all reductions and transforming callbacks unset.
The default counter estimates serialized input at four characters per token. Reports mark these counts as estimates. Provider framing, language, media, and generated tool schemas can change actual usage. Supply a model-aware
count_tokens callback when you need accurate admission checks. A count-based input budget is not a guaranteed billing cap.TokenBudgetExceeded, with budget, limit, and observed numeric attributes. It does not silently shorten the request further, switch models, or invent a successful answer. In a streamed invocation, earlier output may already have reached the caller before a later model attempt is blocked.
Model-call counters are shared across concurrent calls to the same agent in an invocation. They reset for a new runtime invocation, including a resumed invocation; they are not durable spending limits across processes or sessions. Calls and retries inside a provider client are outside this counter.
Keep the original history
History retention and tool-text reduction affect a detached model request. They do not delete messages from the session transcript or checkpoint, or alter the result returned by the tool itself. Disabling a policy lets the framework use its normal history again, subject to your existinghistory setting.
The built-in history reduction removes complete earlier turns. It keeps the latest user turn and its ongoing tool exchanges together, and preserves system/developer instructions. It does not generate summaries. Tool-text reduction preserves identifiers and structured scalar types, and leaves LangGraph non-text media blocks intact. ADK JSON response string values are shortened individually.
Reductions can omit information the agent needs. Choose them for your workload and compare task success, retries, latency, and total token usage. Use your own request transformation when summaries or selected fields are more appropriate than retention and truncation.
Override or disable for one invocation
Use a trusted Python scope around runtime calls:Agent(token_policy=TokenPolicy(enabled=False), ...) to install a disabled adapter for later activation. Agent(token_policy=None, ...), the default, installs no adapter at all.
HTTP request metadata does not enable, relax, or disable token policy. If your application offers caller-selectable profiles, authenticate the caller and choose an allowed policy in trusted Python code. For direct native execution outside a Harnest invocation, token_policy_scope(...) also supplies the state required by max_model_calls.
Supply your own strategies
All strategy callbacks accept ordinary or asynchronous functions. Synchronous model calls require synchronous strategies. Harnest does not call an additional model unless your strategy does so.
The order is: count original input, apply configured built-in reductions, run
request_transform, run tool_selector, count the resulting input, check budgets, then dispatch. Harnest retains the original tool ordering when selecting tools to avoid unnecessary prompt-prefix changes. The selector cannot add tools or expand an agent’s permissions.
For example, restrict exposed tools using an application-owned set:
TokenRequest exposes framework, model, messages, system, tools, settings, and read-only-by-contract context_metadata. ADK messages use Google Content dictionaries. LangGraph messages use LangChain’s messages_to_dict representation; their content is under data. System values also use the framework’s representation. Settings are native generation options, so a provider-specific strategy should branch on framework.
A request transformation may edit messages, system instructions, and generation settings. It cannot change the framework, model, tool descriptors, or context_metadata. Use tool_selector for selection. Keep tool-call/result pairing, native message metadata, and any required instructions intact when supplying your own summarizer. context_metadata includes additional provider tool or output-schema information for counters, not writable provider settings.
TokenReport distinguishes input_before and input_after counts from provider-reported input_tokens, output_tokens, and total_tokens. Cache-read and reasoning counts are included when available. Missing provider usage remains None. Reports include the agent name, admitted/attempted model-call number, removed message/tool counts, exceeded budgets, and a phase of before, after, blocked, or error. Observer failures log a content-free warning and do not interrupt model execution.