headroom-ai 0.1.0 → 0.22.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +300 -14
- package/dist/adapters/anthropic.cjs +6 -2
- package/dist/adapters/anthropic.cjs.map +1 -1
- package/dist/adapters/anthropic.d.cts +1 -1
- package/dist/adapters/anthropic.d.ts +1 -1
- package/dist/adapters/anthropic.js +6 -2
- package/dist/adapters/anthropic.js.map +1 -1
- package/dist/adapters/gemini.cjs +41 -0
- package/dist/adapters/gemini.cjs.map +1 -0
- package/dist/adapters/gemini.d.cts +31 -0
- package/dist/adapters/gemini.d.ts +31 -0
- package/dist/adapters/gemini.js +39 -0
- package/dist/adapters/gemini.js.map +1 -0
- package/dist/adapters/openai.cjs +6 -2
- package/dist/adapters/openai.cjs.map +1 -1
- package/dist/adapters/openai.d.cts +1 -1
- package/dist/adapters/openai.d.ts +1 -1
- package/dist/adapters/openai.js +6 -2
- package/dist/adapters/openai.js.map +1 -1
- package/dist/adapters/vercel-ai.cjs +33 -8
- package/dist/adapters/vercel-ai.cjs.map +1 -1
- package/dist/adapters/vercel-ai.d.cts +30 -2
- package/dist/adapters/vercel-ai.d.ts +30 -2
- package/dist/adapters/vercel-ai.js +28 -5
- package/dist/adapters/vercel-ai.js.map +1 -1
- package/dist/chunk-7AJIWIPP.js +1108 -0
- package/dist/chunk-7AJIWIPP.js.map +1 -0
- package/dist/chunk-R6FB52AD.cjs +1139 -0
- package/dist/chunk-R6FB52AD.cjs.map +1 -0
- package/dist/index.cjs +430 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +797 -18
- package/dist/index.d.ts +797 -18
- package/dist/index.js +326 -1
- package/dist/index.js.map +1 -1
- package/dist/types-BTrX7__W.d.cts +149 -0
- package/dist/types-BTrX7__W.d.ts +149 -0
- package/package.json +12 -2
- package/dist/chunk-3N25JEWK.cjs +0 -538
- package/dist/chunk-3N25JEWK.cjs.map +0 -1
- package/dist/chunk-YTTW7S2Q.js +0 -526
- package/dist/chunk-YTTW7S2Q.js.map +0 -1
- package/dist/types-DQtcLXq3.d.cts +0 -87
- package/dist/types-DQtcLXq3.d.ts +0 -87
package/README.md
CHANGED
|
@@ -30,18 +30,29 @@ Requires a running Headroom proxy (`headroom proxy`) or Headroom Cloud API key.
|
|
|
30
30
|
### Vercel AI SDK
|
|
31
31
|
|
|
32
32
|
```typescript
|
|
33
|
-
import {
|
|
34
|
-
import { wrapLanguageModel, generateText } from 'ai';
|
|
33
|
+
import { withHeadroom } from 'headroom-ai/vercel-ai';
|
|
35
34
|
import { openai } from '@ai-sdk/openai';
|
|
35
|
+
import { generateText } from 'ai';
|
|
36
|
+
|
|
37
|
+
const model = withHeadroom(openai('gpt-4o'));
|
|
38
|
+
const { text } = await generateText({ model, messages });
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
<details>
|
|
42
|
+
<summary>Advanced: using middleware directly</summary>
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
import { headroomMiddleware } from 'headroom-ai/vercel-ai';
|
|
46
|
+
import { wrapLanguageModel } from 'ai';
|
|
36
47
|
|
|
37
48
|
const model = wrapLanguageModel({
|
|
38
49
|
model: openai('gpt-4o'),
|
|
39
|
-
middleware: headroomMiddleware(),
|
|
50
|
+
middleware: headroomMiddleware({ baseUrl: 'http://localhost:8787' }),
|
|
40
51
|
});
|
|
41
|
-
|
|
42
|
-
const { text } = await generateText({ model, messages });
|
|
43
52
|
```
|
|
44
53
|
|
|
54
|
+
</details>
|
|
55
|
+
|
|
45
56
|
### OpenAI SDK
|
|
46
57
|
|
|
47
58
|
```typescript
|
|
@@ -69,6 +80,278 @@ const response = await client.messages.create({
|
|
|
69
80
|
});
|
|
70
81
|
```
|
|
71
82
|
|
|
83
|
+
### Google Gemini
|
|
84
|
+
|
|
85
|
+
```typescript
|
|
86
|
+
import { withHeadroom } from 'headroom-ai/gemini';
|
|
87
|
+
import { GoogleGenerativeAI } from '@google/generative-ai';
|
|
88
|
+
|
|
89
|
+
const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);
|
|
90
|
+
const model = withHeadroom(genAI.getGenerativeModel({ model: 'gemini-2.0-flash' }));
|
|
91
|
+
|
|
92
|
+
const result = await model.generateContent({
|
|
93
|
+
contents: longConversation,
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## HeadroomClient
|
|
98
|
+
|
|
99
|
+
The full client provides direct access to the proxy's OpenAI and Anthropic passthrough endpoints, plus metrics, CCR, and observability.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { HeadroomClient } from 'headroom-ai';
|
|
103
|
+
|
|
104
|
+
const client = new HeadroomClient({
|
|
105
|
+
baseUrl: 'http://localhost:8787',
|
|
106
|
+
providerApiKey: process.env.OPENAI_API_KEY,
|
|
107
|
+
config: {
|
|
108
|
+
smartCrusher: { enabled: true, maxItemsAfterCrush: 10 },
|
|
109
|
+
ccr: { enabled: true },
|
|
110
|
+
},
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Chat Completions (OpenAI-style)
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const response = await client.chat.completions.create({
|
|
118
|
+
model: 'gpt-4o',
|
|
119
|
+
messages: longConversation,
|
|
120
|
+
headroomMode: 'optimize',
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Messages (Anthropic-style)
|
|
125
|
+
|
|
126
|
+
```typescript
|
|
127
|
+
const response = await client.messages.create({
|
|
128
|
+
model: 'claude-sonnet-4-5-20250929',
|
|
129
|
+
messages: longConversation,
|
|
130
|
+
max_tokens: 1024,
|
|
131
|
+
headroomMode: 'optimize',
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Direct Compression
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const result = await client.compress(messages, { model: 'gpt-4o', tokenBudget: 4000 });
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Simulation (Dry Run)
|
|
142
|
+
|
|
143
|
+
See what compression would do without calling the LLM.
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import { simulate } from 'headroom-ai';
|
|
147
|
+
|
|
148
|
+
const sim = await simulate(messages, { model: 'gpt-4o' });
|
|
149
|
+
console.log(`Would save ${sim.tokensSaved} tokens (${sim.estimatedSavings})`);
|
|
150
|
+
console.log('Transforms:', sim.transforms);
|
|
151
|
+
console.log('Waste signals:', sim.wasteSignals);
|
|
152
|
+
console.log('Cache alignment:', sim.cacheAlignmentScore);
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Also available on the client:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
const sim = await client.chat.completions.simulate({
|
|
159
|
+
model: 'gpt-4o',
|
|
160
|
+
messages,
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
## Compression Hooks
|
|
165
|
+
|
|
166
|
+
Customize compression with pre/post hooks — matching the Python `CompressionHooks` API.
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { compress, CompressionHooks } from 'headroom-ai';
|
|
170
|
+
import type { CompressContext, CompressEvent } from 'headroom-ai';
|
|
171
|
+
|
|
172
|
+
class MyHooks extends CompressionHooks {
|
|
173
|
+
// Modify messages before compression
|
|
174
|
+
preCompress(messages: any[], ctx: CompressContext) {
|
|
175
|
+
return [{ role: 'system', content: 'Always preserve error details.' }, ...messages];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Set per-message importance biases
|
|
179
|
+
computeBiases(messages: any[], ctx: CompressContext) {
|
|
180
|
+
return { 0: 2.0 }; // preserve first message
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Observe compression results
|
|
184
|
+
postCompress(event: CompressEvent) {
|
|
185
|
+
console.log(`Saved ${event.tokensSaved} tokens via ${event.transformsApplied.join(', ')}`);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const result = await compress(messages, { model: 'gpt-4o', hooks: new MyHooks() });
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## SharedContext (Multi-Agent)
|
|
193
|
+
|
|
194
|
+
Compressed inter-agent context sharing — matching the Python `SharedContext` API.
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
import { SharedContext } from 'headroom-ai';
|
|
198
|
+
|
|
199
|
+
const ctx = new SharedContext({ model: 'gpt-4o', ttl: 3600, maxEntries: 100 });
|
|
200
|
+
|
|
201
|
+
// Agent A stores data (automatically compressed)
|
|
202
|
+
const entry = await ctx.put('research', bigAgentOutput, { agent: 'researcher' });
|
|
203
|
+
console.log(`Compressed: ${entry.savingsPercent.toFixed(0)}% savings`);
|
|
204
|
+
|
|
205
|
+
// Agent B reads it (~80% smaller)
|
|
206
|
+
const summary = ctx.get('research');
|
|
207
|
+
|
|
208
|
+
// Agent B gets original if needed
|
|
209
|
+
const full = ctx.get('research', { full: true });
|
|
210
|
+
|
|
211
|
+
// Stats
|
|
212
|
+
const stats = ctx.stats();
|
|
213
|
+
console.log(`${stats.entries} entries, ${stats.totalTokensSaved} tokens saved`);
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
## CCR Retrieve (Compress-Cache-Retrieve)
|
|
217
|
+
|
|
218
|
+
Retrieve original content when the LLM needs full details.
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
const result = await client.compress(messages, { model: 'gpt-4o' });
|
|
222
|
+
|
|
223
|
+
// Later, when the LLM calls headroom_retrieve:
|
|
224
|
+
for (const hash of result.ccrHashes) {
|
|
225
|
+
const original = await client.retrieve(hash);
|
|
226
|
+
console.log(`${original.originalTokens} original tokens for ${original.toolName}`);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Search within compressed content
|
|
230
|
+
const search = await client.retrieve('abc123', { query: 'error logs' });
|
|
231
|
+
|
|
232
|
+
// Handle LLM tool calls in an agent loop
|
|
233
|
+
const toolResult = await client.handleToolCall({
|
|
234
|
+
toolCall: assistantMessage.tool_calls[0],
|
|
235
|
+
provider: 'openai',
|
|
236
|
+
});
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Metrics & Observability
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
// Proxy health
|
|
243
|
+
const health = await client.health();
|
|
244
|
+
// → { status: 'healthy', version: '0.5.18', config: { optimize: true, ... } }
|
|
245
|
+
|
|
246
|
+
// Proxy stats
|
|
247
|
+
const stats = await client.proxyStats();
|
|
248
|
+
// → { requests: { total, cached, failed }, tokens: { saved, savingsPercent }, ... }
|
|
249
|
+
|
|
250
|
+
// Request metrics
|
|
251
|
+
const metrics = await client.getMetrics({ model: 'gpt-4o', limit: 10 });
|
|
252
|
+
|
|
253
|
+
// Summary
|
|
254
|
+
const summary = await client.getSummary();
|
|
255
|
+
|
|
256
|
+
// Validate setup
|
|
257
|
+
const validation = await client.validateSetup();
|
|
258
|
+
|
|
259
|
+
// Clear cache
|
|
260
|
+
await client.clearCache();
|
|
261
|
+
|
|
262
|
+
// Prometheus metrics
|
|
263
|
+
const prom = await client.prometheusMetrics();
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## Telemetry, Feedback & TOIN
|
|
267
|
+
|
|
268
|
+
Access the proxy's learning systems.
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
// Telemetry
|
|
272
|
+
const telemetry = await client.telemetry.getStats();
|
|
273
|
+
const tools = await client.telemetry.getTools();
|
|
274
|
+
|
|
275
|
+
// Feedback — per-tool compression hints
|
|
276
|
+
const hints = await client.feedback.getHints('list_servers');
|
|
277
|
+
// → { hints: { maxItems: 8, skipCompression: false, preserveFields: ['id', 'status'] } }
|
|
278
|
+
|
|
279
|
+
// TOIN (Tool Output Intelligence Network)
|
|
280
|
+
const toinStats = await client.toin.getStats();
|
|
281
|
+
const patterns = await client.toin.getPatterns(20);
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Configuration Types
|
|
285
|
+
|
|
286
|
+
Full TypeScript interfaces for every Python config dataclass.
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
import type { HeadroomConfig, SmartCrusherConfig, CCRConfig } from 'headroom-ai';
|
|
290
|
+
|
|
291
|
+
const config: HeadroomConfig = {
|
|
292
|
+
defaultMode: 'optimize',
|
|
293
|
+
smartCrusher: {
|
|
294
|
+
enabled: true,
|
|
295
|
+
minItemsToAnalyze: 5,
|
|
296
|
+
maxItemsAfterCrush: 10,
|
|
297
|
+
varianceThreshold: 2.0,
|
|
298
|
+
relevance: { tier: 'hybrid', relevanceThreshold: 0.25 },
|
|
299
|
+
anchor: { anchorBudgetPct: 0.25 },
|
|
300
|
+
},
|
|
301
|
+
ccr: { enabled: true, injectTool: true },
|
|
302
|
+
cacheOptimizer: { enabled: true, autoDetectProvider: true },
|
|
303
|
+
intelligentContext: { enabled: true, useImportanceScoring: true },
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const client = new HeadroomClient({ config });
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Error Handling
|
|
310
|
+
|
|
311
|
+
Full error hierarchy matching the Python SDK.
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
import {
|
|
315
|
+
HeadroomError,
|
|
316
|
+
HeadroomConnectionError,
|
|
317
|
+
HeadroomAuthError,
|
|
318
|
+
HeadroomCompressError,
|
|
319
|
+
ConfigurationError,
|
|
320
|
+
ProviderError,
|
|
321
|
+
StorageError,
|
|
322
|
+
TokenizationError,
|
|
323
|
+
CacheError,
|
|
324
|
+
ValidationError,
|
|
325
|
+
TransformError,
|
|
326
|
+
} from 'headroom-ai';
|
|
327
|
+
|
|
328
|
+
try {
|
|
329
|
+
await client.compress(messages);
|
|
330
|
+
} catch (err) {
|
|
331
|
+
if (err instanceof HeadroomAuthError) {
|
|
332
|
+
console.error('Auth failed — check HEADROOM_API_KEY');
|
|
333
|
+
} else if (err instanceof HeadroomCompressError) {
|
|
334
|
+
console.error(`Compression error ${err.statusCode}: ${err.errorType}`);
|
|
335
|
+
} else if (err instanceof ConfigurationError) {
|
|
336
|
+
console.error('Bad config:', err.details);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
## Format Detection & Conversion
|
|
342
|
+
|
|
343
|
+
Auto-detects and converts between OpenAI, Anthropic, Vercel AI SDK, and Gemini formats.
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
import { detectFormat, toOpenAI, fromOpenAI } from 'headroom-ai';
|
|
347
|
+
|
|
348
|
+
const format = detectFormat(messages); // 'openai' | 'anthropic' | 'vercel' | 'gemini'
|
|
349
|
+
const openaiMessages = toOpenAI(messages);
|
|
350
|
+
const back = fromOpenAI(openaiMessages, format);
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
The `compress()` function handles this automatically — pass any format and get the same format back.
|
|
354
|
+
|
|
72
355
|
## Configuration
|
|
73
356
|
|
|
74
357
|
```typescript
|
|
@@ -81,6 +364,8 @@ const result = await compress(messages, {
|
|
|
81
364
|
timeout: 30000, // ms
|
|
82
365
|
fallback: true, // return uncompressed if proxy is down (default)
|
|
83
366
|
retries: 1, // retry on transient failures (default)
|
|
367
|
+
tokenBudget: 4000, // compress to fit this limit
|
|
368
|
+
hooks: new MyHooks(), // pre/post compression hooks
|
|
84
369
|
});
|
|
85
370
|
```
|
|
86
371
|
|
|
@@ -88,19 +373,20 @@ Or use environment variables:
|
|
|
88
373
|
- `HEADROOM_BASE_URL` — proxy/cloud URL
|
|
89
374
|
- `HEADROOM_API_KEY` — Cloud API key
|
|
90
375
|
|
|
91
|
-
##
|
|
376
|
+
## Utilities
|
|
92
377
|
|
|
93
378
|
```typescript
|
|
94
|
-
|
|
379
|
+
// Case conversion for proxy communication
|
|
380
|
+
import { deepCamelCase, deepSnakeCase } from 'headroom-ai';
|
|
95
381
|
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
382
|
+
const tsObj = deepCamelCase({ tokens_before: 100 }); // { tokensBefore: 100 }
|
|
383
|
+
const pyObj = deepSnakeCase({ tokensBefore: 100 }); // { tokens_before: 100 }
|
|
384
|
+
|
|
385
|
+
// SSE stream parsing
|
|
386
|
+
import { parseSSE, collectStream } from 'headroom-ai';
|
|
100
387
|
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
const r2 = await client.compress(messages2, { model: 'gpt-4o' });
|
|
388
|
+
// Hook helpers
|
|
389
|
+
import { extractUserQuery, countTurns, extractToolCalls } from 'headroom-ai';
|
|
104
390
|
```
|
|
105
391
|
|
|
106
392
|
## License
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkR6FB52AD_cjs = require('../chunk-R6FB52AD.cjs');
|
|
4
4
|
|
|
5
5
|
// src/adapters/anthropic.ts
|
|
6
6
|
function anthropicToOpenAI(messages) {
|
|
@@ -120,7 +120,11 @@ function withHeadroom(client, options = {}) {
|
|
|
120
120
|
const messages = params.messages;
|
|
121
121
|
const model = options.model ?? params.model ?? "claude-sonnet-4-5-20250929";
|
|
122
122
|
const openaiMessages = anthropicToOpenAI(messages);
|
|
123
|
-
const result = await
|
|
123
|
+
const result = await chunkR6FB52AD_cjs.compress(openaiMessages, {
|
|
124
|
+
stack: "adapter_ts_anthropic",
|
|
125
|
+
...options,
|
|
126
|
+
model
|
|
127
|
+
});
|
|
124
128
|
const anthropicMessages = result.compressed ? openAIToAnthropic(result.messages) : messages;
|
|
125
129
|
return originalCreate({
|
|
126
130
|
...params,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/anthropic.ts"],"names":["compress"],"mappings":"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","file":"anthropic.cjs","sourcesContent":["import { compress } from \"../compress.js\";\nimport type { CompressOptions, OpenAIMessage } from \"../types.js\";\nimport type { AssistantMessage, ToolCall } from \"../types.js\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\ninterface AnthropicLike {\n messages: {\n create: (params: any) => any;\n };\n [key: string]: any;\n}\n\n/**\n * Convert Anthropic messages to OpenAI format for compression.\n *\n * Anthropic format:\n * { role: 'user' | 'assistant', content: string | ContentBlock[] }\n * ContentBlock = { type: 'text', text } | { type: 'tool_use', ... } | { type: 'tool_result', ... }\n */\nfunction anthropicToOpenAI(messages: any[]): OpenAIMessage[] {\n const result: OpenAIMessage[] = [];\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") {\n result.push({ role: \"user\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n const toolResults = msg.content.filter(\n (b: any) => b.type === \"tool_result\",\n );\n const textBlocks = msg.content.filter((b: any) => b.type === \"text\");\n\n if (textBlocks.length > 0) {\n result.push({\n role: \"user\",\n content: textBlocks.map((b: any) => b.text).join(\"\\n\"),\n });\n }\n for (const tr of toolResults) {\n result.push({\n role: \"tool\",\n content:\n typeof tr.content === \"string\"\n ? tr.content\n : JSON.stringify(tr.content),\n tool_call_id: tr.tool_use_id,\n });\n }\n }\n continue;\n }\n\n if (msg.role === \"assistant\") {\n if (typeof msg.content === \"string\") {\n result.push({ role: \"assistant\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n const textBlocks = msg.content.filter((b: any) => b.type === \"text\");\n const toolUseBlocks = msg.content.filter(\n (b: any) => b.type === \"tool_use\",\n );\n\n const content =\n textBlocks.length > 0\n ? textBlocks.map((b: any) => b.text).join(\"\\n\")\n : null;\n\n const openaiMsg: AssistantMessage = { role: \"assistant\", content };\n if (toolUseBlocks.length > 0) {\n openaiMsg.tool_calls = toolUseBlocks.map(\n (b: any): ToolCall => ({\n id: b.id,\n type: \"function\",\n function: {\n name: b.name,\n arguments: JSON.stringify(b.input),\n },\n }),\n );\n }\n result.push(openaiMsg);\n }\n continue;\n }\n }\n\n return result;\n}\n\n/**\n * Convert compressed OpenAI messages back to Anthropic format.\n */\nfunction openAIToAnthropic(messages: OpenAIMessage[]): any[] {\n const result: any[] = [];\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") {\n result.push({ role: \"user\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n result.push({\n role: \"user\",\n content: msg.content.map((p) => {\n if (p.type === \"text\") return { type: \"text\", text: p.text };\n return { type: \"text\", text: \"\" };\n }),\n });\n }\n continue;\n }\n\n if (msg.role === \"assistant\") {\n const blocks: any[] = [];\n if (msg.content) blocks.push({ type: \"text\", text: msg.content });\n if (msg.tool_calls) {\n for (const tc of msg.tool_calls) {\n blocks.push({\n type: \"tool_use\",\n id: tc.id,\n name: tc.function.name,\n input: JSON.parse(tc.function.arguments),\n });\n }\n }\n result.push({\n role: \"assistant\",\n content:\n blocks.length === 1 && blocks[0].type === \"text\"\n ? blocks[0].text\n : blocks,\n });\n continue;\n }\n\n if (msg.role === \"tool\") {\n result.push({\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: msg.tool_call_id,\n content: msg.content,\n },\n ],\n });\n continue;\n }\n\n if (msg.role === \"system\") {\n // System messages are handled separately in Anthropic (as `system` param)\n // Pass through as user message if it appears in the messages array\n result.push({ role: \"user\", content: msg.content });\n }\n }\n\n return result;\n}\n\n/**\n * Wrap an Anthropic client to auto-compress messages before each request.\n *\n * Intercepts `client.messages.create()` only. All other methods pass through.\n *\n * @example\n * ```typescript\n * import { withHeadroom } from 'headroom-ai/anthropic';\n * import Anthropic from '@anthropic-ai/sdk';\n *\n * const client = withHeadroom(new Anthropic());\n * const response = await client.messages.create({\n * model: 'claude-sonnet-4-5-20250929',\n * messages: longConversation,\n * max_tokens: 1024,\n * });\n * ```\n */\nexport function withHeadroom<T extends AnthropicLike>(\n client: T,\n options: CompressOptions = {},\n): T {\n const originalCreate = client.messages.create.bind(client.messages);\n\n const compressedCreate = async (params: any) => {\n const messages = params.messages;\n const model =\n options.model ?? params.model ?? \"claude-sonnet-4-5-20250929\";\n\n const openaiMessages = anthropicToOpenAI(messages);\n const result = await compress(openaiMessages, { ...options, model });\n\n const anthropicMessages = result.compressed\n ? openAIToAnthropic(result.messages)\n : messages;\n\n return originalCreate({\n ...params,\n messages: anthropicMessages,\n });\n };\n\n const messagesProxy = new Proxy(client.messages, {\n get(target, prop) {\n if (prop === \"create\") return compressedCreate;\n return (target as any)[prop];\n },\n });\n\n return new Proxy(client, {\n get(target, prop) {\n if (prop === \"messages\") return messagesProxy;\n return (target as any)[prop];\n },\n }) as T;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/anthropic.ts"],"names":["compress"],"mappings":"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","file":"anthropic.cjs","sourcesContent":["import { compress } from \"../compress.js\";\nimport type { CompressOptions, OpenAIMessage } from \"../types.js\";\nimport type { AssistantMessage, ToolCall } from \"../types.js\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\ninterface AnthropicLike {\n messages: {\n create: (params: any) => any;\n };\n [key: string]: any;\n}\n\n/**\n * Convert Anthropic messages to OpenAI format for compression.\n *\n * Anthropic format:\n * { role: 'user' | 'assistant', content: string | ContentBlock[] }\n * ContentBlock = { type: 'text', text } | { type: 'tool_use', ... } | { type: 'tool_result', ... }\n */\nfunction anthropicToOpenAI(messages: any[]): OpenAIMessage[] {\n const result: OpenAIMessage[] = [];\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") {\n result.push({ role: \"user\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n const toolResults = msg.content.filter(\n (b: any) => b.type === \"tool_result\",\n );\n const textBlocks = msg.content.filter((b: any) => b.type === \"text\");\n\n if (textBlocks.length > 0) {\n result.push({\n role: \"user\",\n content: textBlocks.map((b: any) => b.text).join(\"\\n\"),\n });\n }\n for (const tr of toolResults) {\n result.push({\n role: \"tool\",\n content:\n typeof tr.content === \"string\"\n ? tr.content\n : JSON.stringify(tr.content),\n tool_call_id: tr.tool_use_id,\n });\n }\n }\n continue;\n }\n\n if (msg.role === \"assistant\") {\n if (typeof msg.content === \"string\") {\n result.push({ role: \"assistant\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n const textBlocks = msg.content.filter((b: any) => b.type === \"text\");\n const toolUseBlocks = msg.content.filter(\n (b: any) => b.type === \"tool_use\",\n );\n\n const content =\n textBlocks.length > 0\n ? textBlocks.map((b: any) => b.text).join(\"\\n\")\n : null;\n\n const openaiMsg: AssistantMessage = { role: \"assistant\", content };\n if (toolUseBlocks.length > 0) {\n openaiMsg.tool_calls = toolUseBlocks.map(\n (b: any): ToolCall => ({\n id: b.id,\n type: \"function\",\n function: {\n name: b.name,\n arguments: JSON.stringify(b.input),\n },\n }),\n );\n }\n result.push(openaiMsg);\n }\n continue;\n }\n }\n\n return result;\n}\n\n/**\n * Convert compressed OpenAI messages back to Anthropic format.\n */\nfunction openAIToAnthropic(messages: OpenAIMessage[]): any[] {\n const result: any[] = [];\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") {\n result.push({ role: \"user\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n result.push({\n role: \"user\",\n content: msg.content.map((p) => {\n if (p.type === \"text\") return { type: \"text\", text: p.text };\n return { type: \"text\", text: \"\" };\n }),\n });\n }\n continue;\n }\n\n if (msg.role === \"assistant\") {\n const blocks: any[] = [];\n if (msg.content) blocks.push({ type: \"text\", text: msg.content });\n if (msg.tool_calls) {\n for (const tc of msg.tool_calls) {\n blocks.push({\n type: \"tool_use\",\n id: tc.id,\n name: tc.function.name,\n input: JSON.parse(tc.function.arguments),\n });\n }\n }\n result.push({\n role: \"assistant\",\n content:\n blocks.length === 1 && blocks[0].type === \"text\"\n ? blocks[0].text\n : blocks,\n });\n continue;\n }\n\n if (msg.role === \"tool\") {\n result.push({\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: msg.tool_call_id,\n content: msg.content,\n },\n ],\n });\n continue;\n }\n\n if (msg.role === \"system\") {\n // System messages are handled separately in Anthropic (as `system` param)\n // Pass through as user message if it appears in the messages array\n result.push({ role: \"user\", content: msg.content });\n }\n }\n\n return result;\n}\n\n/**\n * Wrap an Anthropic client to auto-compress messages before each request.\n *\n * Intercepts `client.messages.create()` only. All other methods pass through.\n *\n * @example\n * ```typescript\n * import { withHeadroom } from 'headroom-ai/anthropic';\n * import Anthropic from '@anthropic-ai/sdk';\n *\n * const client = withHeadroom(new Anthropic());\n * const response = await client.messages.create({\n * model: 'claude-sonnet-4-5-20250929',\n * messages: longConversation,\n * max_tokens: 1024,\n * });\n * ```\n */\nexport function withHeadroom<T extends AnthropicLike>(\n client: T,\n options: CompressOptions = {},\n): T {\n const originalCreate = client.messages.create.bind(client.messages);\n\n const compressedCreate = async (params: any) => {\n const messages = params.messages;\n const model =\n options.model ?? params.model ?? \"claude-sonnet-4-5-20250929\";\n\n const openaiMessages = anthropicToOpenAI(messages);\n const result = await compress(openaiMessages, {\n stack: \"adapter_ts_anthropic\",\n ...options,\n model,\n });\n\n const anthropicMessages = result.compressed\n ? openAIToAnthropic(result.messages)\n : messages;\n\n return originalCreate({\n ...params,\n messages: anthropicMessages,\n });\n };\n\n const messagesProxy = new Proxy(client.messages, {\n get(target, prop) {\n if (prop === \"create\") return compressedCreate;\n return (target as any)[prop];\n },\n });\n\n return new Proxy(client, {\n get(target, prop) {\n if (prop === \"messages\") return messagesProxy;\n return (target as any)[prop];\n },\n }) as T;\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { compress } from '../chunk-
|
|
1
|
+
import { compress } from '../chunk-7AJIWIPP.js';
|
|
2
2
|
|
|
3
3
|
// src/adapters/anthropic.ts
|
|
4
4
|
function anthropicToOpenAI(messages) {
|
|
@@ -118,7 +118,11 @@ function withHeadroom(client, options = {}) {
|
|
|
118
118
|
const messages = params.messages;
|
|
119
119
|
const model = options.model ?? params.model ?? "claude-sonnet-4-5-20250929";
|
|
120
120
|
const openaiMessages = anthropicToOpenAI(messages);
|
|
121
|
-
const result = await compress(openaiMessages, {
|
|
121
|
+
const result = await compress(openaiMessages, {
|
|
122
|
+
stack: "adapter_ts_anthropic",
|
|
123
|
+
...options,
|
|
124
|
+
model
|
|
125
|
+
});
|
|
122
126
|
const anthropicMessages = result.compressed ? openAIToAnthropic(result.messages) : messages;
|
|
123
127
|
return originalCreate({
|
|
124
128
|
...params,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/adapters/anthropic.ts"],"names":[],"mappings":";;;AAoBA,SAAS,kBAAkB,QAAA,EAAkC;AAC3D,EAAA,MAAM,SAA0B,EAAC;AAEjC,EAAA,KAAA,MAAW,OAAO,QAAA,EAAU;AAC1B,IAAA,IAAI,GAAA,CAAI,SAAS,MAAA,EAAQ;AACvB,MAAA,IAAI,OAAO,GAAA,CAAI,OAAA,KAAY,QAAA,EAAU;AACnC,QAAA,MAAA,CAAO,KAAK,EAAE,IAAA,EAAM,QAAQ,OAAA,EAAS,GAAA,CAAI,SAAS,CAAA;AAAA,MACpD,CAAA,MAAA,IAAW,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,OAAO,CAAA,EAAG;AACrC,QAAA,MAAM,WAAA,GAAc,IAAI,OAAA,CAAQ,MAAA;AAAA,UAC9B,CAAC,CAAA,KAAW,CAAA,CAAE,IAAA,KAAS;AAAA,SACzB;AACA,QAAA,MAAM,UAAA,GAAa,IAAI,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAW,CAAA,CAAE,SAAS,MAAM,CAAA;AAEnE,QAAA,IAAI,UAAA,CAAW,SAAS,CAAA,EAAG;AACzB,UAAA,MAAA,CAAO,IAAA,CAAK;AAAA,YACV,IAAA,EAAM,MAAA;AAAA,YACN,OAAA,EAAS,WAAW,GAAA,CAAI,CAAC,MAAW,CAAA,CAAE,IAAI,CAAA,CAAE,IAAA,CAAK,IAAI;AAAA,WACtD,CAAA;AAAA,QACH;AACA,QAAA,KAAA,MAAW,MAAM,WAAA,EAAa;AAC5B,UAAA,MAAA,CAAO,IAAA,CAAK;AAAA,YACV,IAAA,EAAM,MAAA;AAAA,YACN,OAAA,EACE,OAAO,EAAA,CAAG,OAAA,KAAY,QAAA,GAClB,GAAG,OAAA,GACH,IAAA,CAAK,SAAA,CAAU,EAAA,CAAG,OAAO,CAAA;AAAA,YAC/B,cAAc,EAAA,CAAG;AAAA,WAClB,CAAA;AAAA,QACH;AAAA,MACF;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,GAAA,CAAI,SAAS,WAAA,EAAa;AAC5B,MAAA,IAAI,OAAO,GAAA,CAAI,OAAA,KAAY,QAAA,EAAU;AACnC,QAAA,MAAA,CAAO,KAAK,EAAE,IAAA,EAAM,aAAa,OAAA,EAAS,GAAA,CAAI,SAAS,CAAA;AAAA,MACzD,CAAA,MAAA,IAAW,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,OAAO,CAAA,EAAG;AACrC,QAAA,MAAM,UAAA,GAAa,IAAI,OAAA,CAAQ,MAAA,CAAO,CAAC,CAAA,KAAW,CAAA,CAAE,SAAS,MAAM,CAAA;AACnE,QAAA,MAAM,aAAA,GAAgB,IAAI,OAAA,CAAQ,MAAA;AAAA,UAChC,CAAC,CAAA,KAAW,CAAA,CAAE,IAAA,KAAS;AAAA,SACzB;AAEA,QAAA,MAAM,OAAA,GACJ,UAAA,CAAW,MAAA,GAAS,CAAA,GAChB,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,KAAW,CAAA,CAAE,IAAI,CAAA,CAAE,IAAA,CAAK,IAAI,CAAA,GAC5C,IAAA;AAEN,QAAA,MAAM,SAAA,GAA8B,EAAE,IAAA,EAAM,WAAA,EAAa,OAAA,EAAQ;AACjE,QAAA,IAAI,aAAA,CAAc,SAAS,CAAA,EAAG;AAC5B,UAAA,SAAA,CAAU,aAAa,aAAA,CAAc,GAAA;AAAA,YACnC,CAAC,CAAA,MAAsB;AAAA,cACrB,IAAI,CAAA,CAAE,EAAA;AAAA,cACN,IAAA,EAAM,UAAA;AAAA,cACN,QAAA,EAAU;AAAA,gBACR,MAAM,CAAA,CAAE,IAAA;AAAA,gBACR,SAAA,EAAW,IAAA,CAAK,SAAA,CAAU,CAAA,CAAE,KAAK;AAAA;AACnC,aACF;AAAA,WACF;AAAA,QACF;AACA,QAAA,MAAA,CAAO,KAAK,SAAS,CAAA;AAAA,MACvB;AACA,MAAA;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAKA,SAAS,kBAAkB,QAAA,EAAkC;AAC3D,EAAA,MAAM,SAAgB,EAAC;AAEvB,EAAA,KAAA,MAAW,OAAO,QAAA,EAAU;AAC1B,IAAA,IAAI,GAAA,CAAI,SAAS,MAAA,EAAQ;AACvB,MAAA,IAAI,OAAO,GAAA,CAAI,OAAA,KAAY,QAAA,EAAU;AACnC,QAAA,MAAA,CAAO,KAAK,EAAE,IAAA,EAAM,QAAQ,OAAA,EAAS,GAAA,CAAI,SAAS,CAAA;AAAA,MACpD,CAAA,MAAA,IAAW,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,OAAO,CAAA,EAAG;AACrC,QAAA,MAAA,CAAO,IAAA,CAAK;AAAA,UACV,IAAA,EAAM,MAAA;AAAA,UACN,OAAA,EAAS,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM;AAC9B,YAAA,IAAI,CAAA,CAAE,SAAS,MAAA,EAAQ,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,CAAA,CAAE,IAAA,EAAK;AAC3D,YAAA,OAAO,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,EAAA,EAAG;AAAA,UAClC,CAAC;AAAA,SACF,CAAA;AAAA,MACH;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,GAAA,CAAI,SAAS,WAAA,EAAa;AAC5B,MAAA,MAAM,SAAgB,EAAC;AACvB,MAAA,IAAI,GAAA,CAAI,OAAA,EAAS,MAAA,CAAO,IAAA,CAAK,EAAE,MAAM,MAAA,EAAQ,IAAA,EAAM,GAAA,CAAI,OAAA,EAAS,CAAA;AAChE,MAAA,IAAI,IAAI,UAAA,EAAY;AAClB,QAAA,KAAA,MAAW,EAAA,IAAM,IAAI,UAAA,EAAY;AAC/B,UAAA,MAAA,CAAO,IAAA,CAAK;AAAA,YACV,IAAA,EAAM,UAAA;AAAA,YACN,IAAI,EAAA,CAAG,EAAA;AAAA,YACP,IAAA,EAAM,GAAG,QAAA,CAAS,IAAA;AAAA,YAClB,KAAA,EAAO,IAAA,CAAK,KAAA,CAAM,EAAA,CAAG,SAAS,SAAS;AAAA,WACxC,CAAA;AAAA,QACH;AAAA,MACF;AACA,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,WAAA;AAAA,QACN,OAAA,EACE,MAAA,CAAO,MAAA,KAAW,CAAA,IAAK,MAAA,CAAO,CAAC,CAAA,CAAE,IAAA,KAAS,MAAA,GACtC,MAAA,CAAO,CAAC,CAAA,CAAE,IAAA,GACV;AAAA,OACP,CAAA;AACD,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,GAAA,CAAI,SAAS,MAAA,EAAQ;AACvB,MAAA,MAAA,CAAO,IAAA,CAAK;AAAA,QACV,IAAA,EAAM,MAAA;AAAA,QACN,OAAA,EAAS;AAAA,UACP;AAAA,YACE,IAAA,EAAM,aAAA;AAAA,YACN,aAAa,GAAA,CAAI,YAAA;AAAA,YACjB,SAAS,GAAA,CAAI;AAAA;AACf;AACF,OACD,CAAA;AACD,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,GAAA,CAAI,SAAS,QAAA,EAAU;AAGzB,MAAA,MAAA,CAAO,KAAK,EAAE,IAAA,EAAM,QAAQ,OAAA,EAAS,GAAA,CAAI,SAAS,CAAA;AAAA,IACpD;AAAA,EACF;AAEA,EAAA,OAAO,MAAA;AACT;AAoBO,SAAS,YAAA,CACd,MAAA,EACA,OAAA,GAA2B,EAAC,EACzB;AACH,EAAA,MAAM,iBAAiB,MAAA,CAAO,QAAA,CAAS,MAAA,CAAO,IAAA,CAAK,OAAO,QAAQ,CAAA;AAElE,EAAA,MAAM,gBAAA,GAAmB,OAAO,MAAA,KAAgB;AAC9C,IAAA,MAAM,WAAW,MAAA,CAAO,QAAA;AACxB,IAAA,MAAM,KAAA,GACJ,OAAA,CAAQ,KAAA,IAAS,MAAA,CAAO,KAAA,IAAS,4BAAA;AAEnC,IAAA,MAAM,cAAA,GAAiB,kBAAkB,QAAQ,CAAA;AACjD,IAAA,MAAM,MAAA,GAAS,MAAM,QAAA,CAAS,cAAA,EAAgB,EAAE,GAAG,OAAA,EAAS,OAAO,CAAA;AAEnE,IAAA,MAAM,oBAAoB,MAAA,CAAO,UAAA,GAC7B,iBAAA,CAAkB,MAAA,CAAO,QAAQ,CAAA,GACjC,QAAA;AAEJ,IAAA,OAAO,cAAA,CAAe;AAAA,MACpB,GAAG,MAAA;AAAA,MACH,QAAA,EAAU;AAAA,KACX,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,aAAA,GAAgB,IAAI,KAAA,CAAM,MAAA,CAAO,QAAA,EAAU;AAAA,IAC/C,GAAA,CAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,IAAI,IAAA,KAAS,UAAU,OAAO,gBAAA;AAC9B,MAAA,OAAQ,OAAe,IAAI,CAAA;AAAA,IAC7B;AAAA,GACD,CAAA;AAED,EAAA,OAAO,IAAI,MAAM,MAAA,EAAQ;AAAA,IACvB,GAAA,CAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,IAAI,IAAA,KAAS,YAAY,OAAO,aAAA;AAChC,MAAA,OAAQ,OAAe,IAAI,CAAA;AAAA,IAC7B;AAAA,GACD,CAAA;AACH","file":"anthropic.js","sourcesContent":["import { compress } from \"../compress.js\";\nimport type { CompressOptions, OpenAIMessage } from \"../types.js\";\nimport type { AssistantMessage, ToolCall } from \"../types.js\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\ninterface AnthropicLike {\n messages: {\n create: (params: any) => any;\n };\n [key: string]: any;\n}\n\n/**\n * Convert Anthropic messages to OpenAI format for compression.\n *\n * Anthropic format:\n * { role: 'user' | 'assistant', content: string | ContentBlock[] }\n * ContentBlock = { type: 'text', text } | { type: 'tool_use', ... } | { type: 'tool_result', ... }\n */\nfunction anthropicToOpenAI(messages: any[]): OpenAIMessage[] {\n const result: OpenAIMessage[] = [];\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") {\n result.push({ role: \"user\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n const toolResults = msg.content.filter(\n (b: any) => b.type === \"tool_result\",\n );\n const textBlocks = msg.content.filter((b: any) => b.type === \"text\");\n\n if (textBlocks.length > 0) {\n result.push({\n role: \"user\",\n content: textBlocks.map((b: any) => b.text).join(\"\\n\"),\n });\n }\n for (const tr of toolResults) {\n result.push({\n role: \"tool\",\n content:\n typeof tr.content === \"string\"\n ? tr.content\n : JSON.stringify(tr.content),\n tool_call_id: tr.tool_use_id,\n });\n }\n }\n continue;\n }\n\n if (msg.role === \"assistant\") {\n if (typeof msg.content === \"string\") {\n result.push({ role: \"assistant\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n const textBlocks = msg.content.filter((b: any) => b.type === \"text\");\n const toolUseBlocks = msg.content.filter(\n (b: any) => b.type === \"tool_use\",\n );\n\n const content =\n textBlocks.length > 0\n ? textBlocks.map((b: any) => b.text).join(\"\\n\")\n : null;\n\n const openaiMsg: AssistantMessage = { role: \"assistant\", content };\n if (toolUseBlocks.length > 0) {\n openaiMsg.tool_calls = toolUseBlocks.map(\n (b: any): ToolCall => ({\n id: b.id,\n type: \"function\",\n function: {\n name: b.name,\n arguments: JSON.stringify(b.input),\n },\n }),\n );\n }\n result.push(openaiMsg);\n }\n continue;\n }\n }\n\n return result;\n}\n\n/**\n * Convert compressed OpenAI messages back to Anthropic format.\n */\nfunction openAIToAnthropic(messages: OpenAIMessage[]): any[] {\n const result: any[] = [];\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") {\n result.push({ role: \"user\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n result.push({\n role: \"user\",\n content: msg.content.map((p) => {\n if (p.type === \"text\") return { type: \"text\", text: p.text };\n return { type: \"text\", text: \"\" };\n }),\n });\n }\n continue;\n }\n\n if (msg.role === \"assistant\") {\n const blocks: any[] = [];\n if (msg.content) blocks.push({ type: \"text\", text: msg.content });\n if (msg.tool_calls) {\n for (const tc of msg.tool_calls) {\n blocks.push({\n type: \"tool_use\",\n id: tc.id,\n name: tc.function.name,\n input: JSON.parse(tc.function.arguments),\n });\n }\n }\n result.push({\n role: \"assistant\",\n content:\n blocks.length === 1 && blocks[0].type === \"text\"\n ? blocks[0].text\n : blocks,\n });\n continue;\n }\n\n if (msg.role === \"tool\") {\n result.push({\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: msg.tool_call_id,\n content: msg.content,\n },\n ],\n });\n continue;\n }\n\n if (msg.role === \"system\") {\n // System messages are handled separately in Anthropic (as `system` param)\n // Pass through as user message if it appears in the messages array\n result.push({ role: \"user\", content: msg.content });\n }\n }\n\n return result;\n}\n\n/**\n * Wrap an Anthropic client to auto-compress messages before each request.\n *\n * Intercepts `client.messages.create()` only. All other methods pass through.\n *\n * @example\n * ```typescript\n * import { withHeadroom } from 'headroom-ai/anthropic';\n * import Anthropic from '@anthropic-ai/sdk';\n *\n * const client = withHeadroom(new Anthropic());\n * const response = await client.messages.create({\n * model: 'claude-sonnet-4-5-20250929',\n * messages: longConversation,\n * max_tokens: 1024,\n * });\n * ```\n */\nexport function withHeadroom<T extends AnthropicLike>(\n client: T,\n options: CompressOptions = {},\n): T {\n const originalCreate = client.messages.create.bind(client.messages);\n\n const compressedCreate = async (params: any) => {\n const messages = params.messages;\n const model =\n options.model ?? params.model ?? \"claude-sonnet-4-5-20250929\";\n\n const openaiMessages = anthropicToOpenAI(messages);\n const result = await compress(openaiMessages, { ...options, model });\n\n const anthropicMessages = result.compressed\n ? openAIToAnthropic(result.messages)\n : messages;\n\n return originalCreate({\n ...params,\n messages: anthropicMessages,\n });\n };\n\n const messagesProxy = new Proxy(client.messages, {\n get(target, prop) {\n if (prop === \"create\") return compressedCreate;\n return (target as any)[prop];\n },\n });\n\n return new Proxy(client, {\n get(target, prop) {\n if (prop === \"messages\") return messagesProxy;\n return (target as any)[prop];\n },\n }) as T;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/anthropic.ts"],"names":[],"mappings":"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","file":"anthropic.js","sourcesContent":["import { compress } from \"../compress.js\";\nimport type { CompressOptions, OpenAIMessage } from \"../types.js\";\nimport type { AssistantMessage, ToolCall } from \"../types.js\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\ninterface AnthropicLike {\n messages: {\n create: (params: any) => any;\n };\n [key: string]: any;\n}\n\n/**\n * Convert Anthropic messages to OpenAI format for compression.\n *\n * Anthropic format:\n * { role: 'user' | 'assistant', content: string | ContentBlock[] }\n * ContentBlock = { type: 'text', text } | { type: 'tool_use', ... } | { type: 'tool_result', ... }\n */\nfunction anthropicToOpenAI(messages: any[]): OpenAIMessage[] {\n const result: OpenAIMessage[] = [];\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") {\n result.push({ role: \"user\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n const toolResults = msg.content.filter(\n (b: any) => b.type === \"tool_result\",\n );\n const textBlocks = msg.content.filter((b: any) => b.type === \"text\");\n\n if (textBlocks.length > 0) {\n result.push({\n role: \"user\",\n content: textBlocks.map((b: any) => b.text).join(\"\\n\"),\n });\n }\n for (const tr of toolResults) {\n result.push({\n role: \"tool\",\n content:\n typeof tr.content === \"string\"\n ? tr.content\n : JSON.stringify(tr.content),\n tool_call_id: tr.tool_use_id,\n });\n }\n }\n continue;\n }\n\n if (msg.role === \"assistant\") {\n if (typeof msg.content === \"string\") {\n result.push({ role: \"assistant\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n const textBlocks = msg.content.filter((b: any) => b.type === \"text\");\n const toolUseBlocks = msg.content.filter(\n (b: any) => b.type === \"tool_use\",\n );\n\n const content =\n textBlocks.length > 0\n ? textBlocks.map((b: any) => b.text).join(\"\\n\")\n : null;\n\n const openaiMsg: AssistantMessage = { role: \"assistant\", content };\n if (toolUseBlocks.length > 0) {\n openaiMsg.tool_calls = toolUseBlocks.map(\n (b: any): ToolCall => ({\n id: b.id,\n type: \"function\",\n function: {\n name: b.name,\n arguments: JSON.stringify(b.input),\n },\n }),\n );\n }\n result.push(openaiMsg);\n }\n continue;\n }\n }\n\n return result;\n}\n\n/**\n * Convert compressed OpenAI messages back to Anthropic format.\n */\nfunction openAIToAnthropic(messages: OpenAIMessage[]): any[] {\n const result: any[] = [];\n\n for (const msg of messages) {\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") {\n result.push({ role: \"user\", content: msg.content });\n } else if (Array.isArray(msg.content)) {\n result.push({\n role: \"user\",\n content: msg.content.map((p) => {\n if (p.type === \"text\") return { type: \"text\", text: p.text };\n return { type: \"text\", text: \"\" };\n }),\n });\n }\n continue;\n }\n\n if (msg.role === \"assistant\") {\n const blocks: any[] = [];\n if (msg.content) blocks.push({ type: \"text\", text: msg.content });\n if (msg.tool_calls) {\n for (const tc of msg.tool_calls) {\n blocks.push({\n type: \"tool_use\",\n id: tc.id,\n name: tc.function.name,\n input: JSON.parse(tc.function.arguments),\n });\n }\n }\n result.push({\n role: \"assistant\",\n content:\n blocks.length === 1 && blocks[0].type === \"text\"\n ? blocks[0].text\n : blocks,\n });\n continue;\n }\n\n if (msg.role === \"tool\") {\n result.push({\n role: \"user\",\n content: [\n {\n type: \"tool_result\",\n tool_use_id: msg.tool_call_id,\n content: msg.content,\n },\n ],\n });\n continue;\n }\n\n if (msg.role === \"system\") {\n // System messages are handled separately in Anthropic (as `system` param)\n // Pass through as user message if it appears in the messages array\n result.push({ role: \"user\", content: msg.content });\n }\n }\n\n return result;\n}\n\n/**\n * Wrap an Anthropic client to auto-compress messages before each request.\n *\n * Intercepts `client.messages.create()` only. All other methods pass through.\n *\n * @example\n * ```typescript\n * import { withHeadroom } from 'headroom-ai/anthropic';\n * import Anthropic from '@anthropic-ai/sdk';\n *\n * const client = withHeadroom(new Anthropic());\n * const response = await client.messages.create({\n * model: 'claude-sonnet-4-5-20250929',\n * messages: longConversation,\n * max_tokens: 1024,\n * });\n * ```\n */\nexport function withHeadroom<T extends AnthropicLike>(\n client: T,\n options: CompressOptions = {},\n): T {\n const originalCreate = client.messages.create.bind(client.messages);\n\n const compressedCreate = async (params: any) => {\n const messages = params.messages;\n const model =\n options.model ?? params.model ?? \"claude-sonnet-4-5-20250929\";\n\n const openaiMessages = anthropicToOpenAI(messages);\n const result = await compress(openaiMessages, {\n stack: \"adapter_ts_anthropic\",\n ...options,\n model,\n });\n\n const anthropicMessages = result.compressed\n ? openAIToAnthropic(result.messages)\n : messages;\n\n return originalCreate({\n ...params,\n messages: anthropicMessages,\n });\n };\n\n const messagesProxy = new Proxy(client.messages, {\n get(target, prop) {\n if (prop === \"create\") return compressedCreate;\n return (target as any)[prop];\n },\n });\n\n return new Proxy(client, {\n get(target, prop) {\n if (prop === \"messages\") return messagesProxy;\n return (target as any)[prop];\n },\n }) as T;\n}\n"]}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkR6FB52AD_cjs = require('../chunk-R6FB52AD.cjs');
|
|
4
|
+
|
|
5
|
+
// src/adapters/gemini.ts
|
|
6
|
+
function withHeadroom(model, options = {}) {
|
|
7
|
+
const originalGenerate = model.generateContent.bind(model);
|
|
8
|
+
const originalStream = model.generateContentStream?.bind(model);
|
|
9
|
+
const compressedGenerate = async (params) => {
|
|
10
|
+
const contents = params.contents ?? params;
|
|
11
|
+
const modelName = options.model ?? "gemini-2.0-flash";
|
|
12
|
+
const result = await chunkR6FB52AD_cjs.compress(
|
|
13
|
+
Array.isArray(contents) ? contents : [contents],
|
|
14
|
+
{ stack: "adapter_ts_gemini", ...options, model: modelName }
|
|
15
|
+
);
|
|
16
|
+
const newParams = Array.isArray(params) ? result.messages : { ...params, contents: result.messages };
|
|
17
|
+
return originalGenerate(newParams);
|
|
18
|
+
};
|
|
19
|
+
const compressedStream = originalStream ? async (params) => {
|
|
20
|
+
const contents = params.contents ?? params;
|
|
21
|
+
const modelName = options.model ?? "gemini-2.0-flash";
|
|
22
|
+
const result = await chunkR6FB52AD_cjs.compress(
|
|
23
|
+
Array.isArray(contents) ? contents : [contents],
|
|
24
|
+
{ stack: "adapter_ts_gemini", ...options, model: modelName }
|
|
25
|
+
);
|
|
26
|
+
const newParams = Array.isArray(params) ? result.messages : { ...params, contents: result.messages };
|
|
27
|
+
return originalStream(newParams);
|
|
28
|
+
} : void 0;
|
|
29
|
+
return new Proxy(model, {
|
|
30
|
+
get(target, prop) {
|
|
31
|
+
if (prop === "generateContent") return compressedGenerate;
|
|
32
|
+
if (prop === "generateContentStream" && compressedStream)
|
|
33
|
+
return compressedStream;
|
|
34
|
+
return target[prop];
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
exports.withHeadroom = withHeadroom;
|
|
40
|
+
//# sourceMappingURL=gemini.cjs.map
|
|
41
|
+
//# sourceMappingURL=gemini.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/gemini.ts"],"names":["compress"],"mappings":";;;;;AAgCO,SAAS,YAAA,CACd,KAAA,EACA,OAAA,GAA2B,EAAC,EACzB;AACH,EAAA,MAAM,gBAAA,GAAmB,KAAA,CAAM,eAAA,CAAgB,IAAA,CAAK,KAAK,CAAA;AACzD,EAAA,MAAM,cAAA,GAAiB,KAAA,CAAM,qBAAA,EAAuB,IAAA,CAAK,KAAK,CAAA;AAE9D,EAAA,MAAM,kBAAA,GAAqB,OAAO,MAAA,KAAgB;AAChD,IAAA,MAAM,QAAA,GAAW,OAAO,QAAA,IAAY,MAAA;AACpC,IAAA,MAAM,SAAA,GAAY,QAAQ,KAAA,IAAS,kBAAA;AAGnC,IAAA,MAAM,SAAS,MAAMA,0BAAA;AAAA,MACnB,MAAM,OAAA,CAAQ,QAAQ,CAAA,GAAI,QAAA,GAAW,CAAC,QAAQ,CAAA;AAAA,MAC9C,EAAE,KAAA,EAAO,mBAAA,EAAqB,GAAG,OAAA,EAAS,OAAO,SAAA;AAAU,KAC7D;AAEA,IAAA,MAAM,SAAA,GAAY,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,GAClC,MAAA,CAAO,QAAA,GACP,EAAE,GAAG,MAAA,EAAQ,QAAA,EAAU,MAAA,CAAO,QAAA,EAAS;AAE3C,IAAA,OAAO,iBAAiB,SAAS,CAAA;AAAA,EACnC,CAAA;AAEA,EAAA,MAAM,gBAAA,GAAmB,cAAA,GACrB,OAAO,MAAA,KAAgB;AACrB,IAAA,MAAM,QAAA,GAAW,OAAO,QAAA,IAAY,MAAA;AACpC,IAAA,MAAM,SAAA,GAAY,QAAQ,KAAA,IAAS,kBAAA;AAEnC,IAAA,MAAM,SAAS,MAAMA,0BAAA;AAAA,MACnB,MAAM,OAAA,CAAQ,QAAQ,CAAA,GAAI,QAAA,GAAW,CAAC,QAAQ,CAAA;AAAA,MAC9C,EAAE,KAAA,EAAO,mBAAA,EAAqB,GAAG,OAAA,EAAS,OAAO,SAAA;AAAU,KAC7D;AAEA,IAAA,MAAM,SAAA,GAAY,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,GAClC,MAAA,CAAO,QAAA,GACP,EAAE,GAAG,MAAA,EAAQ,QAAA,EAAU,MAAA,CAAO,QAAA,EAAS;AAE3C,IAAA,OAAO,eAAe,SAAS,CAAA;AAAA,EACjC,CAAA,GACA,MAAA;AAEJ,EAAA,OAAO,IAAI,MAAM,KAAA,EAAO;AAAA,IACtB,GAAA,CAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,IAAI,IAAA,KAAS,mBAAmB,OAAO,kBAAA;AACvC,MAAA,IAAI,SAAS,uBAAA,IAA2B,gBAAA;AACtC,QAAA,OAAO,gBAAA;AACT,MAAA,OAAQ,OAAe,IAAI,CAAA;AAAA,IAC7B;AAAA,GACD,CAAA;AACH","file":"gemini.cjs","sourcesContent":["/**\n * Gemini adapter — wraps Google Generative AI model with auto-compression.\n * Matches the pattern of openai.ts and anthropic.ts adapters.\n */\n\nimport { compress } from \"../compress.js\";\nimport type { CompressOptions } from \"../types.js\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\ninterface GeminiModelLike {\n generateContent: (params: any) => any;\n generateContentStream?: (params: any) => any;\n [key: string]: any;\n}\n\n/**\n * Wrap a Google Generative AI model to auto-compress before each request.\n *\n * Intercepts `model.generateContent()` and `model.generateContentStream()`.\n *\n * @example\n * ```typescript\n * import { withHeadroom } from 'headroom-ai/gemini';\n * import { GoogleGenerativeAI } from '@google/generative-ai';\n *\n * const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);\n * const model = withHeadroom(genAI.getGenerativeModel({ model: 'gemini-2.0-flash' }));\n *\n * const result = await model.generateContent({ contents: longConversation });\n * ```\n */\nexport function withHeadroom<T extends GeminiModelLike>(\n model: T,\n options: CompressOptions = {},\n): T {\n const originalGenerate = model.generateContent.bind(model);\n const originalStream = model.generateContentStream?.bind(model);\n\n const compressedGenerate = async (params: any) => {\n const contents = params.contents ?? params;\n const modelName = options.model ?? \"gemini-2.0-flash\";\n\n // compress() auto-detects Gemini format\n const result = await compress(\n Array.isArray(contents) ? contents : [contents],\n { stack: \"adapter_ts_gemini\", ...options, model: modelName },\n );\n\n const newParams = Array.isArray(params)\n ? result.messages\n : { ...params, contents: result.messages };\n\n return originalGenerate(newParams);\n };\n\n const compressedStream = originalStream\n ? async (params: any) => {\n const contents = params.contents ?? params;\n const modelName = options.model ?? \"gemini-2.0-flash\";\n\n const result = await compress(\n Array.isArray(contents) ? contents : [contents],\n { stack: \"adapter_ts_gemini\", ...options, model: modelName },\n );\n\n const newParams = Array.isArray(params)\n ? result.messages\n : { ...params, contents: result.messages };\n\n return originalStream(newParams);\n }\n : undefined;\n\n return new Proxy(model, {\n get(target, prop) {\n if (prop === \"generateContent\") return compressedGenerate;\n if (prop === \"generateContentStream\" && compressedStream)\n return compressedStream;\n return (target as any)[prop];\n },\n }) as T;\n}\n"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { C as CompressOptions } from '../types-BTrX7__W.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gemini adapter — wraps Google Generative AI model with auto-compression.
|
|
5
|
+
* Matches the pattern of openai.ts and anthropic.ts adapters.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
interface GeminiModelLike {
|
|
9
|
+
generateContent: (params: any) => any;
|
|
10
|
+
generateContentStream?: (params: any) => any;
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Wrap a Google Generative AI model to auto-compress before each request.
|
|
15
|
+
*
|
|
16
|
+
* Intercepts `model.generateContent()` and `model.generateContentStream()`.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { withHeadroom } from 'headroom-ai/gemini';
|
|
21
|
+
* import { GoogleGenerativeAI } from '@google/generative-ai';
|
|
22
|
+
*
|
|
23
|
+
* const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);
|
|
24
|
+
* const model = withHeadroom(genAI.getGenerativeModel({ model: 'gemini-2.0-flash' }));
|
|
25
|
+
*
|
|
26
|
+
* const result = await model.generateContent({ contents: longConversation });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare function withHeadroom<T extends GeminiModelLike>(model: T, options?: CompressOptions): T;
|
|
30
|
+
|
|
31
|
+
export { withHeadroom };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { C as CompressOptions } from '../types-BTrX7__W.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gemini adapter — wraps Google Generative AI model with auto-compression.
|
|
5
|
+
* Matches the pattern of openai.ts and anthropic.ts adapters.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
interface GeminiModelLike {
|
|
9
|
+
generateContent: (params: any) => any;
|
|
10
|
+
generateContentStream?: (params: any) => any;
|
|
11
|
+
[key: string]: any;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Wrap a Google Generative AI model to auto-compress before each request.
|
|
15
|
+
*
|
|
16
|
+
* Intercepts `model.generateContent()` and `model.generateContentStream()`.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* import { withHeadroom } from 'headroom-ai/gemini';
|
|
21
|
+
* import { GoogleGenerativeAI } from '@google/generative-ai';
|
|
22
|
+
*
|
|
23
|
+
* const genAI = new GoogleGenerativeAI(process.env.GEMINI_API_KEY!);
|
|
24
|
+
* const model = withHeadroom(genAI.getGenerativeModel({ model: 'gemini-2.0-flash' }));
|
|
25
|
+
*
|
|
26
|
+
* const result = await model.generateContent({ contents: longConversation });
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
declare function withHeadroom<T extends GeminiModelLike>(model: T, options?: CompressOptions): T;
|
|
30
|
+
|
|
31
|
+
export { withHeadroom };
|