[//]: # (dependabot-start) ⚠️ **Dependabot is rebasing this PR** ⚠️ Rebasing might not happen immediately, so don't worry if this takes some time. Note: if you make any changes to this PR yourself, they will take precedence over the rebase. --- [//]: # (dependabot-end) Bumps the npm_and_yarn group with 1 update in the /docs directory: [js-yaml](https://github.com/nodeca/js-yaml). Bumps the npm_and_yarn group with 1 update in the /plugins/openclaw directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite). Bumps the npm_and_yarn group with 2 updates in the /sdk/typescript directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) and [form-data](https://github.com/form-data/form-data). Updates `js-yaml` from 4.1.1 to 4.2.0 <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md">js-yaml's changelog</a>.</em></p> <blockquote> <h2>[4.2.0] - 2026-06-01</h2> <h3>Added</h3> <ul> <li>Added <code>docs/safety.md</code> with notes about processing untrusted YAML.</li> <li>Added <code>maxDepth</code> (100) loader option. Not a problem, but gives a better exception instead of RangeError on stack overflow.</li> <li>Added <code>maxMergeSeqLength</code> (20) loader option. Not a problem after <code>merge</code> fix, but an additional restriction for safety.</li> <li>Added sourcemaps to <code>dist/</code> builds.</li> </ul> <h3>Changed</h3> <ul> <li>Stop resolving numbers with underscores as numeric scalars, <a href="https://redirect.github.com/nodeca/js-yaml/issues/627">#627</a>.</li> <li>Switched dev toolchains to Vite / neostandard.</li> <li>Updated demo.</li> <li>Reorganized tests.</li> <li><code>dist/</code> files are no longer kept in the repository.</li> </ul> <h3>Fixed</h3> <ul> <li>Fix parsing of properties on the first implicit block mapping key, <a href="https://redirect.github.com/nodeca/js-yaml/issues/62">#62</a>.</li> <li>Fix trailing whitespace handling when folding flow scalar lines, <a href="https://redirect.github.com/nodeca/js-yaml/issues/307">#307</a>.</li> <li>Reject top-level block scalars without content indentation, <a href="https://redirect.github.com/nodeca/js-yaml/issues/280">#280</a>.</li> <li>Ensure numbers survive round-trip, <a href="https://redirect.github.com/nodeca/js-yaml/issues/737">#737</a>.</li> <li>Fix test coverage for issue <a href="https://redirect.github.com/nodeca/js-yaml/issues/221">#221</a>.</li> <li>Fix flow scalar trailing whitespace folding, <a href="https://redirect.github.com/nodeca/js-yaml/issues/307">#307</a>.</li> <li>Fix digits in YAML named tag handles.</li> </ul> <h3>Security</h3> <ul> <li>Fix potential DoS via quadratic complexity in merge - deduplicate repeated elements (makes sense for malformed files > 10K).</li> </ul> <h2>[3.14.2] - 2025-11-15</h2> <h3>Security</h3> <ul> <li>Backported v4.1.1 fix to v3</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/nodeca/js-yaml/commits">compare view</a></li> </ul> </details> <br /> Updates `vite` from 8.0.10 to 8.0.16 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/vitejs/vite/releases">vite's releases</a>.</em></p> <blockquote> <h2>v8.0.16</h2> <p>Please refer to <a href="https://github.com/vitejs/vite/blob/v8.0.16/packages/vite/CHANGELOG.md">CHANGELOG.md</a> for details.</p> <h2>v8.0.15</h2> <p>Please refer to <a href="https://github.com/vitejs/vite/blob/v8.0.15/packages/vite/CHANGELOG.md">CHANGELOG.md</a> for details.</p> <h2>v8.0.14</h2> <p>Please refer to <a href="https://github.com/vitejs/vite/blob/v8.0.14/packages/vite/CHANGELOG.md">CHANGELOG.md</a> for details.</p> <h2>v8.0.13</h2> <p>Please refer to <a href="https://github.com/vitejs/vite/blob/v8.0.13/packages/vite/CHANGELOG.md">CHANGELOG.md</a> for details.</p> <h2>v8.0.12</h2> <p>Please refer to <a href="https://github.com/vitejs/vite/blob/v8.0.12/packages/vite/CHANGELOG.md">CHANGELOG.md</a> for details.</p> <h2>v8.0.11</h2> <p>Please refer to <a href="https://github.com/vitejs/vite/blob/v8.0.11/packages/vite/CHANGELOG.md">CHANGELOG.md</a> for details.</p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md">vite's changelog</a>.</em></p> <blockquote> <h2><!-- raw HTML omitted --><a href="https://github.com/vitejs/vite/compare/v8.0.15...v8.0.16">8.0.16</a> (2026-06-01)<!-- raw HTML omitted --></h2> <h3>Bug Fixes</h3> <ul> <li><strong>deps:</strong> reject UNC paths for launch-editor-middleware (<a href="https://redirect.github.com/vitejs/vite/issues/22571">#22571</a>) (<a href=" |
||
|---|---|---|
| .. | ||
| examples | ||
| src | ||
| test | ||
| .gitignore | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
| tsup.config.ts | ||
| vitest.config.ts | ||
headroom-ai
Compress LLM context. Save tokens. Fit more into every request.
Install
npm install headroom-ai
Quick Start
import { compress } from 'headroom-ai';
const result = await compress(messages, { model: 'gpt-4o' });
console.log(`Saved ${result.tokensSaved} tokens (${((1 - result.compressionRatio) * 100).toFixed(0)}%)`);
// Use compressed messages with any LLM client
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: result.messages,
});
Requires a running Headroom proxy (headroom proxy) or Headroom Cloud API key.
Framework Adapters
Vercel AI SDK
import { withHeadroom } from 'headroom-ai/vercel-ai';
import { openai } from '@ai-sdk/openai';
import { generateText } from 'ai';
const model = withHeadroom(openai('gpt-4o'));
const { text } = await generateText({ model, messages });
Advanced: using middleware directly
import { headroomMiddleware } from 'headroom-ai/vercel-ai';
import { wrapLanguageModel } from 'ai';
const model = wrapLanguageModel({
model: openai('gpt-4o'),
middleware: headroomMiddleware({ baseUrl: 'http://localhost:8787' }),
});
OpenAI SDK
import { withHeadroom } from 'headroom-ai/openai';
import OpenAI from 'openai';
const client = withHeadroom(new OpenAI());
const response = await client.chat.completions.create({
model: 'gpt-4o',
messages: longConversation,
});
Anthropic SDK
import { withHeadroom } from 'headroom-ai/anthropic';
import Anthropic from '@anthropic-ai/sdk';
const client = withHeadroom(new Anthropic());
const response = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
messages: longConversation,
max_tokens: 1024,
});
Google Gemini
import { withHeadroom } from 'headroom-ai/gemini';
import { GoogleGenerativeAI } from '@google/generative-ai';
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);
const model = withHeadroom(genAI.getGenerativeModel({ model: 'gemini-2.0-flash' }));
const result = await model.generateContent({
contents: longConversation,
});
HeadroomClient
The full client provides direct access to the proxy's OpenAI and Anthropic passthrough endpoints, plus metrics, CCR, and observability.
import { HeadroomClient } from 'headroom-ai';
const client = new HeadroomClient({
baseUrl: 'http://localhost:8787',
providerApiKey: process.env.OPENAI_API_KEY,
config: {
smartCrusher: { enabled: true, maxItemsAfterCrush: 10 },
ccr: { enabled: true },
},
});
Chat Completions (OpenAI-style)
const response = await client.chat.completions.create({
model: 'gpt-4o',
messages: longConversation,
headroomMode: 'optimize',
});
Messages (Anthropic-style)
const response = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
messages: longConversation,
max_tokens: 1024,
headroomMode: 'optimize',
});
Direct Compression
const result = await client.compress(messages, { model: 'gpt-4o', tokenBudget: 4000 });
Simulation (Dry Run)
See what compression would do without calling the LLM.
import { simulate } from 'headroom-ai';
const sim = await simulate(messages, { model: 'gpt-4o' });
console.log(`Would save ${sim.tokensSaved} tokens (${sim.estimatedSavings})`);
console.log('Transforms:', sim.transforms);
console.log('Waste signals:', sim.wasteSignals);
console.log('Cache alignment:', sim.cacheAlignmentScore);
Also available on the client:
const sim = await client.chat.completions.simulate({
model: 'gpt-4o',
messages,
});
Compression Hooks
Customize compression with pre/post hooks — matching the Python CompressionHooks API.
import { compress, CompressionHooks } from 'headroom-ai';
import type { CompressContext, CompressEvent } from 'headroom-ai';
class MyHooks extends CompressionHooks {
// Modify messages before compression
preCompress(messages: any[], ctx: CompressContext) {
return [{ role: 'system', content: 'Always preserve error details.' }, ...messages];
}
// Set per-message importance biases
computeBiases(messages: any[], ctx: CompressContext) {
return { 0: 2.0 }; // preserve first message
}
// Observe compression results
postCompress(event: CompressEvent) {
console.log(`Saved ${event.tokensSaved} tokens via ${event.transformsApplied.join(', ')}`);
}
}
const result = await compress(messages, { model: 'gpt-4o', hooks: new MyHooks() });
SharedContext (Multi-Agent)
Compressed inter-agent context sharing — matching the Python SharedContext API.
import { SharedContext } from 'headroom-ai';
const ctx = new SharedContext({ model: 'gpt-4o', ttl: 3600, maxEntries: 100 });
// Agent A stores data (automatically compressed)
const entry = await ctx.put('research', bigAgentOutput, { agent: 'researcher' });
console.log(`Compressed: ${entry.savingsPercent.toFixed(0)}% savings`);
// Agent B reads it (~80% smaller)
const summary = ctx.get('research');
// Agent B gets original if needed
const full = ctx.get('research', { full: true });
// Stats
const stats = ctx.stats();
console.log(`${stats.entries} entries, ${stats.totalTokensSaved} tokens saved`);
CCR Retrieve (Compress-Cache-Retrieve)
Retrieve original content when the LLM needs full details.
const result = await client.compress(messages, { model: 'gpt-4o' });
// Later, when the LLM calls headroom_retrieve:
for (const hash of result.ccrHashes) {
const original = await client.retrieve(hash);
console.log(`${original.originalTokens} original tokens for ${original.toolName}`);
}
// Search within compressed content
const search = await client.retrieve('abc123', { query: 'error logs' });
// Handle LLM tool calls in an agent loop
const toolResult = await client.handleToolCall({
toolCall: assistantMessage.tool_calls[0],
provider: 'openai',
});
Metrics & Observability
// Proxy health
const health = await client.health();
// → { status: 'healthy', version: '0.5.18', config: { optimize: true, ... } }
// Proxy stats
const stats = await client.proxyStats();
// → { requests: { total, cached, failed }, tokens: { saved, savingsPercent }, ... }
// Request metrics
const metrics = await client.getMetrics({ model: 'gpt-4o', limit: 10 });
// Summary
const summary = await client.getSummary();
// Validate setup
const validation = await client.validateSetup();
// Clear cache
await client.clearCache();
// Prometheus metrics
const prom = await client.prometheusMetrics();
Telemetry, Feedback & TOIN
Access the proxy's learning systems.
// Telemetry
const telemetry = await client.telemetry.getStats();
const tools = await client.telemetry.getTools();
// Feedback — per-tool compression hints
const hints = await client.feedback.getHints('list_servers');
// → { hints: { maxItems: 8, skipCompression: false, preserveFields: ['id', 'status'] } }
// TOIN (Tool Output Intelligence Network)
const toinStats = await client.toin.getStats();
const patterns = await client.toin.getPatterns(20);
Configuration Types
Full TypeScript interfaces for every Python config dataclass.
import type { HeadroomConfig, SmartCrusherConfig, CCRConfig } from 'headroom-ai';
const config: HeadroomConfig = {
defaultMode: 'optimize',
smartCrusher: {
enabled: true,
minItemsToAnalyze: 5,
maxItemsAfterCrush: 10,
varianceThreshold: 2.0,
relevance: { tier: 'hybrid', relevanceThreshold: 0.25 },
anchor: { anchorBudgetPct: 0.25 },
},
ccr: { enabled: true, injectTool: true },
cacheOptimizer: { enabled: true, autoDetectProvider: true },
intelligentContext: { enabled: true, useImportanceScoring: true },
};
const client = new HeadroomClient({ config });
Error Handling
Full error hierarchy matching the Python SDK.
import {
HeadroomError,
HeadroomConnectionError,
HeadroomAuthError,
HeadroomCompressError,
ConfigurationError,
ProviderError,
StorageError,
TokenizationError,
CacheError,
ValidationError,
TransformError,
} from 'headroom-ai';
try {
await client.compress(messages);
} catch (err) {
if (err instanceof HeadroomAuthError) {
console.error('Auth failed — check HEADROOM_API_KEY');
} else if (err instanceof HeadroomCompressError) {
console.error(`Compression error ${err.statusCode}: ${err.errorType}`);
} else if (err instanceof ConfigurationError) {
console.error('Bad config:', err.details);
}
}
Format Detection & Conversion
Auto-detects and converts between OpenAI, Anthropic, Vercel AI SDK, and Gemini formats.
import { detectFormat, toOpenAI, fromOpenAI } from 'headroom-ai';
const format = detectFormat(messages); // 'openai' | 'anthropic' | 'vercel' | 'gemini'
const openaiMessages = toOpenAI(messages);
const back = fromOpenAI(openaiMessages, format);
The compress() function handles this automatically — pass any format and get the same format back.
Configuration
import { compress } from 'headroom-ai';
const result = await compress(messages, {
model: 'gpt-4o',
baseUrl: 'http://localhost:8787', // or https://api.headroom.ai
apiKey: 'hr_...', // for Headroom Cloud
timeout: 30000, // ms
fallback: true, // return uncompressed if proxy is down (default)
retries: 1, // retry on transient failures (default)
tokenBudget: 4000, // compress to fit this limit
hooks: new MyHooks(), // pre/post compression hooks
});
Or use environment variables:
HEADROOM_BASE_URL— proxy/cloud URLHEADROOM_API_KEY— Cloud API key
Utilities
// Case conversion for proxy communication
import { deepCamelCase, deepSnakeCase } from 'headroom-ai';
const tsObj = deepCamelCase({ tokens_before: 100 }); // { tokensBefore: 100 }
const pyObj = deepSnakeCase({ tokensBefore: 100 }); // { tokens_before: 100 }
// SSE stream parsing
import { parseSSE, collectStream } from 'headroom-ai';
// Hook helpers
import { extractUserQuery, countTurns, extractToolCalls } from 'headroom-ai';
License
Apache-2.0