Recipes
Token budget compiler
Declare a token budget, let AgentsKit trim messages and summarize history to fit.
Context windows are finite. Long chats, tool-heavy runs, and big
system prompts blow past the limit; the usual response is a random
slice of the last N messages and a prayer. compileBudget replaces
the prayer with a declared budget and three well-defined trimming
strategies.
Install
Built into @agentskit/core — nothing extra to install.
Quick start
import { compileBudget } from '@agentskit/core'
const compiled = await compileBudget({
budget: 16_000,
reserveForOutput: 1_000,
systemPrompt: 'You are a helpful assistant.',
messages: history,
tools: availableTools,
})
if (!compiled.fits) {
console.warn('Still over budget:', compiled.tokens)
}
// Pass compiled.messages + compiled.systemPrompt to your adapter.Strategies
| Strategy | Behavior | Good for |
|---|---|---|
drop-oldest (default) | Remove oldest turns until it fits | Plain chat, no memory of early turns needed |
sliding-window | Keep only the most recent N turns | Agents that care about recency, not history |
summarize | Drop oldest, then fold them into a single summary message | Long-running agents that need some memory of the past |
await compileBudget({
budget: 8_000,
messages,
strategy: 'summarize',
summarizer: async dropped => ({
id: 'summary',
role: 'system',
content: `Summary of ${dropped.length} earlier turns: ...`,
status: 'complete',
createdAt: new Date(),
}),
})Token counter
Defaults to a zero-dependency approximate counter (chars / 4).
Swap in a real tokenizer — tiktoken, provider-specific, your own —
via the counter option:
import type { TokenCounter } from '@agentskit/core'
const tiktokenCounter: TokenCounter = {
name: 'tiktoken',
async count(messages) { /* ... */ },
}
await compileBudget({ budget: 10_000, messages, counter: tiktokenCounter })Result shape
{
messages: Message[], // trimmed (or augmented with summary)
systemPrompt?: string, // unchanged
tokens: {
system: number,
messages: number,
tools: number,
total: number,
budget: number, // budget - reserveForOutput
},
dropped: Message[],
fits: boolean,
strategy: 'drop-oldest' | 'sliding-window' | 'summarize',
}keepRecent protects the last N turns even if the budget can't
accommodate them — fits: false signals that case so you can alert
rather than silently truncate.
See also
- Cost guard — hard dollar ceiling per run
- Deterministic replay