headroom-ai 0.39.0 → 0.40.0

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.
@@ -1,157 +1,20 @@
1
1
  'use strict';
2
2
 
3
- var chunk26N6BVLT_cjs = require('../chunk-26N6BVLT.cjs');
3
+ var chunkN7HYJMEN_cjs = require('../chunk-N7HYJMEN.cjs');
4
4
 
5
5
  // src/adapters/anthropic.ts
6
- function anthropicImageUrl(source) {
7
- if (!source || typeof source !== "object") return null;
8
- if (source.type === "base64" && source.media_type && source.data) {
9
- return `data:${source.media_type};base64,${source.data}`;
10
- }
11
- if (source.type === "url" && typeof source.url === "string") return source.url;
12
- return null;
13
- }
14
- function openAIImageBlock(url) {
15
- const m = /^data:([^;,]+);base64,(.*)$/s.exec(url);
16
- if (m) return { type: "image", source: { type: "base64", media_type: m[1], data: m[2] } };
17
- return { type: "image", source: { type: "url", url } };
18
- }
19
- function anthropicToOpenAI(messages) {
20
- const result = [];
21
- for (const msg of messages) {
22
- if (msg.role === "user") {
23
- if (typeof msg.content === "string") {
24
- result.push({ role: "user", content: msg.content });
25
- } else if (Array.isArray(msg.content)) {
26
- const toolResults = msg.content.filter(
27
- (b) => b.type === "tool_result"
28
- );
29
- const hasImages = msg.content.some((b) => b.type === "image");
30
- if (hasImages) {
31
- const parts = msg.content.filter((b) => b.type === "text" || b.type === "image").map((b) => {
32
- if (b.type === "text") return { type: "text", text: b.text };
33
- const url = anthropicImageUrl(b.source);
34
- return url ? { type: "image_url", image_url: { url } } : null;
35
- }).filter((p) => p !== null);
36
- if (parts.length > 0) {
37
- result.push({ role: "user", content: parts });
38
- }
39
- } else {
40
- const textBlocks = msg.content.filter((b) => b.type === "text");
41
- if (textBlocks.length > 0) {
42
- result.push({
43
- role: "user",
44
- content: textBlocks.map((b) => b.text).join("\n")
45
- });
46
- }
47
- }
48
- for (const tr of toolResults) {
49
- result.push({
50
- role: "tool",
51
- content: typeof tr.content === "string" ? tr.content : JSON.stringify(tr.content),
52
- tool_call_id: tr.tool_use_id
53
- });
54
- }
55
- }
56
- continue;
57
- }
58
- if (msg.role === "assistant") {
59
- if (typeof msg.content === "string") {
60
- result.push({ role: "assistant", content: msg.content });
61
- } else if (Array.isArray(msg.content)) {
62
- const textBlocks = msg.content.filter((b) => b.type === "text");
63
- const toolUseBlocks = msg.content.filter(
64
- (b) => b.type === "tool_use"
65
- );
66
- const content = textBlocks.length > 0 ? textBlocks.map((b) => b.text).join("\n") : null;
67
- const openaiMsg = { role: "assistant", content };
68
- if (toolUseBlocks.length > 0) {
69
- openaiMsg.tool_calls = toolUseBlocks.map(
70
- (b) => ({
71
- id: b.id,
72
- type: "function",
73
- function: {
74
- name: b.name,
75
- arguments: JSON.stringify(b.input)
76
- }
77
- })
78
- );
79
- }
80
- result.push(openaiMsg);
81
- }
82
- continue;
83
- }
84
- }
85
- return result;
86
- }
87
- function openAIToAnthropic(messages) {
88
- const result = [];
89
- for (const msg of messages) {
90
- if (msg.role === "user") {
91
- if (typeof msg.content === "string") {
92
- result.push({ role: "user", content: msg.content });
93
- } else if (Array.isArray(msg.content)) {
94
- result.push({
95
- role: "user",
96
- content: msg.content.map((p) => {
97
- if (p.type === "text") return { type: "text", text: p.text };
98
- if (p.type === "image_url") return openAIImageBlock(p.image_url.url);
99
- return { type: "text", text: "" };
100
- })
101
- });
102
- }
103
- continue;
104
- }
105
- if (msg.role === "assistant") {
106
- const blocks = [];
107
- if (msg.content) blocks.push({ type: "text", text: msg.content });
108
- if (msg.tool_calls) {
109
- for (const tc of msg.tool_calls) {
110
- blocks.push({
111
- type: "tool_use",
112
- id: tc.id,
113
- name: tc.function.name,
114
- input: JSON.parse(tc.function.arguments)
115
- });
116
- }
117
- }
118
- result.push({
119
- role: "assistant",
120
- content: blocks.length === 1 && blocks[0].type === "text" ? blocks[0].text : blocks
121
- });
122
- continue;
123
- }
124
- if (msg.role === "tool") {
125
- result.push({
126
- role: "user",
127
- content: [
128
- {
129
- type: "tool_result",
130
- tool_use_id: msg.tool_call_id,
131
- content: msg.content
132
- }
133
- ]
134
- });
135
- continue;
136
- }
137
- if (msg.role === "system") {
138
- result.push({ role: "user", content: msg.content });
139
- }
140
- }
141
- return result;
142
- }
143
6
  function withHeadroom(client, options = {}) {
144
7
  const originalCreate = client.messages.create.bind(client.messages);
145
8
  const compressedCreate = async (params) => {
146
9
  const messages = params.messages;
147
10
  const model = options.model ?? params.model ?? "claude-sonnet-4-5-20250929";
148
- const openaiMessages = anthropicToOpenAI(messages);
149
- const result = await chunk26N6BVLT_cjs.compress(openaiMessages, {
11
+ const openaiMessages = chunkN7HYJMEN_cjs.anthropicToOpenAI(messages);
12
+ const result = await chunkN7HYJMEN_cjs.compress(openaiMessages, {
150
13
  stack: "adapter_ts_anthropic",
151
14
  ...options,
152
15
  model
153
16
  });
154
- const anthropicMessages = result.compressed ? openAIToAnthropic(result.messages) : messages;
17
+ const anthropicMessages = result.compressed ? chunkN7HYJMEN_cjs.openAIToAnthropic(result.messages) : messages;
155
18
  return originalCreate({
156
19
  ...params,
157
20
  messages: anthropicMessages
@@ -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// Anthropic image block `source` -> OpenAI image_url url string, or null if unconvertible.\nfunction anthropicImageUrl(source: any): string | null {\n if (!source || typeof source !== \"object\") return null;\n if (source.type === \"base64\" && source.media_type && source.data) {\n return `data:${source.media_type};base64,${source.data}`;\n }\n if (source.type === \"url\" && typeof source.url === \"string\") return source.url;\n return null;\n}\n\n// OpenAI image_url url -> Anthropic image block. data: URIs become a base64 source; other urls a url source.\nfunction openAIImageBlock(url: string): any {\n const m = /^data:([^;,]+);base64,(.*)$/s.exec(url);\n if (m) return { type: \"image\", source: { type: \"base64\", media_type: m[1], data: m[2] } };\n return { type: \"image\", source: { type: \"url\", url } };\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 hasImages = msg.content.some((b: any) => b.type === \"image\");\n\n if (hasImages) {\n const parts = msg.content\n .filter((b: any) => b.type === \"text\" || b.type === \"image\")\n .map((b: any) => {\n if (b.type === \"text\") return { type: \"text\" as const, text: b.text };\n const url = anthropicImageUrl(b.source);\n return url ? { type: \"image_url\" as const, image_url: { url } } : null;\n })\n .filter((p: any): p is NonNullable<typeof p> => p !== null);\n\n if (parts.length > 0) {\n result.push({ role: \"user\", content: parts });\n }\n } else {\n const textBlocks = msg.content.filter((b: any) => b.type === \"text\");\n if (textBlocks.length > 0) {\n result.push({\n role: \"user\",\n content: textBlocks.map((b: any) => b.text).join(\"\\n\"),\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 if (p.type === \"image_url\") return openAIImageBlock(p.image_url.url);\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
+ {"version":3,"sources":["../../src/adapters/anthropic.ts"],"names":["anthropicToOpenAI","compress","openAIToAnthropic"],"mappings":";;;;;AA+BO,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,GAAiBA,oCAAkB,QAAQ,CAAA;AACjD,IAAA,MAAM,MAAA,GAAS,MAAMC,0BAAA,CAAS,cAAA,EAAgB;AAAA,MAC5C,KAAA,EAAO,sBAAA;AAAA,MACP,GAAG,OAAA;AAAA,MACH;AAAA,KACD,CAAA;AAED,IAAA,MAAM,oBAAoB,MAAA,CAAO,UAAA,GAC7BC,mCAAA,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.cjs","sourcesContent":["import { compress } from \"../compress.js\";\nimport type { CompressOptions } from \"../types.js\";\nimport { anthropicToOpenAI, openAIToAnthropic } from \"../utils/format.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 * 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,143 +1,6 @@
1
- import { compress } from '../chunk-24W6JPRV.js';
1
+ import { anthropicToOpenAI, compress, openAIToAnthropic } from '../chunk-FJQ65W3R.js';
2
2
 
3
3
  // src/adapters/anthropic.ts
4
- function anthropicImageUrl(source) {
5
- if (!source || typeof source !== "object") return null;
6
- if (source.type === "base64" && source.media_type && source.data) {
7
- return `data:${source.media_type};base64,${source.data}`;
8
- }
9
- if (source.type === "url" && typeof source.url === "string") return source.url;
10
- return null;
11
- }
12
- function openAIImageBlock(url) {
13
- const m = /^data:([^;,]+);base64,(.*)$/s.exec(url);
14
- if (m) return { type: "image", source: { type: "base64", media_type: m[1], data: m[2] } };
15
- return { type: "image", source: { type: "url", url } };
16
- }
17
- function anthropicToOpenAI(messages) {
18
- const result = [];
19
- for (const msg of messages) {
20
- if (msg.role === "user") {
21
- if (typeof msg.content === "string") {
22
- result.push({ role: "user", content: msg.content });
23
- } else if (Array.isArray(msg.content)) {
24
- const toolResults = msg.content.filter(
25
- (b) => b.type === "tool_result"
26
- );
27
- const hasImages = msg.content.some((b) => b.type === "image");
28
- if (hasImages) {
29
- const parts = msg.content.filter((b) => b.type === "text" || b.type === "image").map((b) => {
30
- if (b.type === "text") return { type: "text", text: b.text };
31
- const url = anthropicImageUrl(b.source);
32
- return url ? { type: "image_url", image_url: { url } } : null;
33
- }).filter((p) => p !== null);
34
- if (parts.length > 0) {
35
- result.push({ role: "user", content: parts });
36
- }
37
- } else {
38
- const textBlocks = msg.content.filter((b) => b.type === "text");
39
- if (textBlocks.length > 0) {
40
- result.push({
41
- role: "user",
42
- content: textBlocks.map((b) => b.text).join("\n")
43
- });
44
- }
45
- }
46
- for (const tr of toolResults) {
47
- result.push({
48
- role: "tool",
49
- content: typeof tr.content === "string" ? tr.content : JSON.stringify(tr.content),
50
- tool_call_id: tr.tool_use_id
51
- });
52
- }
53
- }
54
- continue;
55
- }
56
- if (msg.role === "assistant") {
57
- if (typeof msg.content === "string") {
58
- result.push({ role: "assistant", content: msg.content });
59
- } else if (Array.isArray(msg.content)) {
60
- const textBlocks = msg.content.filter((b) => b.type === "text");
61
- const toolUseBlocks = msg.content.filter(
62
- (b) => b.type === "tool_use"
63
- );
64
- const content = textBlocks.length > 0 ? textBlocks.map((b) => b.text).join("\n") : null;
65
- const openaiMsg = { role: "assistant", content };
66
- if (toolUseBlocks.length > 0) {
67
- openaiMsg.tool_calls = toolUseBlocks.map(
68
- (b) => ({
69
- id: b.id,
70
- type: "function",
71
- function: {
72
- name: b.name,
73
- arguments: JSON.stringify(b.input)
74
- }
75
- })
76
- );
77
- }
78
- result.push(openaiMsg);
79
- }
80
- continue;
81
- }
82
- }
83
- return result;
84
- }
85
- function openAIToAnthropic(messages) {
86
- const result = [];
87
- for (const msg of messages) {
88
- if (msg.role === "user") {
89
- if (typeof msg.content === "string") {
90
- result.push({ role: "user", content: msg.content });
91
- } else if (Array.isArray(msg.content)) {
92
- result.push({
93
- role: "user",
94
- content: msg.content.map((p) => {
95
- if (p.type === "text") return { type: "text", text: p.text };
96
- if (p.type === "image_url") return openAIImageBlock(p.image_url.url);
97
- return { type: "text", text: "" };
98
- })
99
- });
100
- }
101
- continue;
102
- }
103
- if (msg.role === "assistant") {
104
- const blocks = [];
105
- if (msg.content) blocks.push({ type: "text", text: msg.content });
106
- if (msg.tool_calls) {
107
- for (const tc of msg.tool_calls) {
108
- blocks.push({
109
- type: "tool_use",
110
- id: tc.id,
111
- name: tc.function.name,
112
- input: JSON.parse(tc.function.arguments)
113
- });
114
- }
115
- }
116
- result.push({
117
- role: "assistant",
118
- content: blocks.length === 1 && blocks[0].type === "text" ? blocks[0].text : blocks
119
- });
120
- continue;
121
- }
122
- if (msg.role === "tool") {
123
- result.push({
124
- role: "user",
125
- content: [
126
- {
127
- type: "tool_result",
128
- tool_use_id: msg.tool_call_id,
129
- content: msg.content
130
- }
131
- ]
132
- });
133
- continue;
134
- }
135
- if (msg.role === "system") {
136
- result.push({ role: "user", content: msg.content });
137
- }
138
- }
139
- return result;
140
- }
141
4
  function withHeadroom(client, options = {}) {
142
5
  const originalCreate = client.messages.create.bind(client.messages);
143
6
  const compressedCreate = async (params) => {
@@ -1 +1 @@
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// Anthropic image block `source` -> OpenAI image_url url string, or null if unconvertible.\nfunction anthropicImageUrl(source: any): string | null {\n if (!source || typeof source !== \"object\") return null;\n if (source.type === \"base64\" && source.media_type && source.data) {\n return `data:${source.media_type};base64,${source.data}`;\n }\n if (source.type === \"url\" && typeof source.url === \"string\") return source.url;\n return null;\n}\n\n// OpenAI image_url url -> Anthropic image block. data: URIs become a base64 source; other urls a url source.\nfunction openAIImageBlock(url: string): any {\n const m = /^data:([^;,]+);base64,(.*)$/s.exec(url);\n if (m) return { type: \"image\", source: { type: \"base64\", media_type: m[1], data: m[2] } };\n return { type: \"image\", source: { type: \"url\", url } };\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 hasImages = msg.content.some((b: any) => b.type === \"image\");\n\n if (hasImages) {\n const parts = msg.content\n .filter((b: any) => b.type === \"text\" || b.type === \"image\")\n .map((b: any) => {\n if (b.type === \"text\") return { type: \"text\" as const, text: b.text };\n const url = anthropicImageUrl(b.source);\n return url ? { type: \"image_url\" as const, image_url: { url } } : null;\n })\n .filter((p: any): p is NonNullable<typeof p> => p !== null);\n\n if (parts.length > 0) {\n result.push({ role: \"user\", content: parts });\n }\n } else {\n const textBlocks = msg.content.filter((b: any) => b.type === \"text\");\n if (textBlocks.length > 0) {\n result.push({\n role: \"user\",\n content: textBlocks.map((b: any) => b.text).join(\"\\n\"),\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 if (p.type === \"image_url\") return openAIImageBlock(p.image_url.url);\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
+ {"version":3,"sources":["../../src/adapters/anthropic.ts"],"names":[],"mappings":";;;AA+BO,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;AAAA,MAC5C,KAAA,EAAO,sBAAA;AAAA,MACP,GAAG,OAAA;AAAA,MACH;AAAA,KACD,CAAA;AAED,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 } from \"../types.js\";\nimport { anthropicToOpenAI, openAIToAnthropic } from \"../utils/format.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 * 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,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk26N6BVLT_cjs = require('../chunk-26N6BVLT.cjs');
3
+ var chunkN7HYJMEN_cjs = require('../chunk-N7HYJMEN.cjs');
4
4
 
5
5
  // src/adapters/gemini.ts
6
6
  function withHeadroom(model, options = {}) {
@@ -9,7 +9,7 @@ function withHeadroom(model, options = {}) {
9
9
  const compressedGenerate = async (params) => {
10
10
  const contents = params.contents ?? params;
11
11
  const modelName = options.model ?? "gemini-2.0-flash";
12
- const result = await chunk26N6BVLT_cjs.compress(
12
+ const result = await chunkN7HYJMEN_cjs.compress(
13
13
  Array.isArray(contents) ? contents : [contents],
14
14
  { stack: "adapter_ts_gemini", ...options, model: modelName }
15
15
  );
@@ -19,7 +19,7 @@ function withHeadroom(model, options = {}) {
19
19
  const compressedStream = originalStream ? async (params) => {
20
20
  const contents = params.contents ?? params;
21
21
  const modelName = options.model ?? "gemini-2.0-flash";
22
- const result = await chunk26N6BVLT_cjs.compress(
22
+ const result = await chunkN7HYJMEN_cjs.compress(
23
23
  Array.isArray(contents) ? contents : [contents],
24
24
  { stack: "adapter_ts_gemini", ...options, model: modelName }
25
25
  );
@@ -1,4 +1,4 @@
1
- import { compress } from '../chunk-24W6JPRV.js';
1
+ import { compress } from '../chunk-FJQ65W3R.js';
2
2
 
3
3
  // src/adapters/gemini.ts
4
4
  function withHeadroom(model, options = {}) {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk26N6BVLT_cjs = require('../chunk-26N6BVLT.cjs');
3
+ var chunkN7HYJMEN_cjs = require('../chunk-N7HYJMEN.cjs');
4
4
 
5
5
  // src/adapters/openai.ts
6
6
  function withHeadroom(client, options = {}) {
@@ -10,7 +10,7 @@ function withHeadroom(client, options = {}) {
10
10
  const compressedCreate = async (params) => {
11
11
  const messages = params.messages;
12
12
  const model = options.model ?? params.model ?? "gpt-4o";
13
- const result = await chunk26N6BVLT_cjs.compress(messages, {
13
+ const result = await chunkN7HYJMEN_cjs.compress(messages, {
14
14
  stack: "adapter_ts_openai",
15
15
  ...options,
16
16
  model
@@ -1,4 +1,4 @@
1
- import { compress } from '../chunk-24W6JPRV.js';
1
+ import { compress } from '../chunk-FJQ65W3R.js';
2
2
 
3
3
  // src/adapters/openai.ts
4
4
  function withHeadroom(client, options = {}) {
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk26N6BVLT_cjs = require('../chunk-26N6BVLT.cjs');
3
+ var chunkN7HYJMEN_cjs = require('../chunk-N7HYJMEN.cjs');
4
4
  var module$1 = require('module');
5
5
 
6
6
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
@@ -12,25 +12,25 @@ function headroomMiddleware(options = {}) {
12
12
  const prompt = params.prompt;
13
13
  if (!prompt || prompt.length === 0) return params;
14
14
  const model = options.model ?? params.modelId ?? "gpt-4o";
15
- const openaiMessages = chunk26N6BVLT_cjs.vercelToOpenAI(prompt);
16
- const result = await chunk26N6BVLT_cjs.compress(openaiMessages, {
15
+ const openaiMessages = chunkN7HYJMEN_cjs.vercelToOpenAI(prompt);
16
+ const result = await chunkN7HYJMEN_cjs.compress(openaiMessages, {
17
17
  stack: "adapter_ts_vercel_ai",
18
18
  ...options,
19
19
  model
20
20
  });
21
21
  if (!result.compressed) return params;
22
- const compressedPrompt = chunk26N6BVLT_cjs.openAIToVercel(result.messages);
22
+ const compressedPrompt = chunkN7HYJMEN_cjs.openAIToVercel(result.messages);
23
23
  return { ...params, prompt: compressedPrompt };
24
24
  }
25
25
  };
26
26
  }
27
27
  async function compressVercelMessages(messages, options = {}) {
28
- const openaiMessages = chunk26N6BVLT_cjs.vercelToOpenAI(messages);
29
- const result = await chunk26N6BVLT_cjs.compress(openaiMessages, {
28
+ const openaiMessages = chunkN7HYJMEN_cjs.vercelToOpenAI(messages);
29
+ const result = await chunkN7HYJMEN_cjs.compress(openaiMessages, {
30
30
  stack: "adapter_ts_vercel_ai",
31
31
  ...options
32
32
  });
33
- const vercelMessages = chunk26N6BVLT_cjs.openAIToVercel(result.messages);
33
+ const vercelMessages = chunkN7HYJMEN_cjs.openAIToVercel(result.messages);
34
34
  return {
35
35
  ...result,
36
36
  messages: vercelMessages
@@ -1,4 +1,4 @@
1
- import { vercelToOpenAI, compress, openAIToVercel } from '../chunk-24W6JPRV.js';
1
+ import { vercelToOpenAI, compress, openAIToVercel } from '../chunk-FJQ65W3R.js';
2
2
  import { createRequire } from 'module';
3
3
 
4
4
  function headroomMiddleware(options = {}) {
@@ -822,6 +822,7 @@ function vercelToOpenAI(messages) {
822
822
  }
823
823
  function openAIToVercel(messages) {
824
824
  const result = [];
825
+ const toolNames = /* @__PURE__ */ new Map();
825
826
  for (const msg of messages) {
826
827
  if (msg.role === "system") {
827
828
  result.push({ role: "system", content: msg.content });
@@ -845,6 +846,7 @@ function openAIToVercel(messages) {
845
846
  if (msg.content) parts.push({ type: "text", text: msg.content });
846
847
  if (msg.tool_calls) {
847
848
  for (const tc of msg.tool_calls) {
849
+ toolNames.set(tc.id, tc.function.name);
848
850
  let input;
849
851
  try {
850
852
  input = JSON.parse(tc.function.arguments);
@@ -876,7 +878,7 @@ function openAIToVercel(messages) {
876
878
  content: [{
877
879
  type: "tool-result",
878
880
  toolCallId: msg.tool_call_id,
879
- toolName: "unknown",
881
+ toolName: toolNames.get(msg.tool_call_id) ?? "unknown",
880
882
  output
881
883
  }]
882
884
  });
@@ -885,6 +887,32 @@ function openAIToVercel(messages) {
885
887
  }
886
888
  return result;
887
889
  }
890
+ function geminiMediaImageUrl(part) {
891
+ const blob = part.inlineData;
892
+ if (blob && typeof blob === "object" && blob.mimeType && blob.data) {
893
+ return { url: `data:${blob.mimeType};base64,${blob.data}` };
894
+ }
895
+ const file = part.fileData;
896
+ if (file && typeof file === "object" && typeof file.fileUri === "string") {
897
+ return typeof file.mimeType === "string" ? { url: file.fileUri, mime_type: file.mimeType } : { url: file.fileUri };
898
+ }
899
+ return null;
900
+ }
901
+ var MIME_BY_EXTENSION = {
902
+ png: "image/png",
903
+ jpg: "image/jpeg",
904
+ jpeg: "image/jpeg",
905
+ gif: "image/gif",
906
+ webp: "image/webp",
907
+ pdf: "application/pdf"
908
+ };
909
+ function geminiMediaPart(imageUrl) {
910
+ const m = /^data:([^;,]+);base64,(.*)$/s.exec(imageUrl.url);
911
+ if (m) return { inlineData: { mimeType: m[1], data: m[2] } };
912
+ const ext = /\.([a-z0-9]+)(?:[?#]|$)/i.exec(imageUrl.url)?.[1]?.toLowerCase();
913
+ const mimeType = imageUrl.mime_type ?? (ext ? MIME_BY_EXTENSION[ext] : void 0);
914
+ return { fileData: mimeType ? { mimeType, fileUri: imageUrl.url } : { fileUri: imageUrl.url } };
915
+ }
888
916
  function geminiToOpenAI(messages) {
889
917
  const result = [];
890
918
  for (const msg of messages) {
@@ -892,9 +920,21 @@ function geminiToOpenAI(messages) {
892
920
  const parts = msg.parts ?? [];
893
921
  if (role === "user") {
894
922
  const funcResponses = parts.filter((p) => p.functionResponse);
895
- const textParts = parts.filter((p) => p.text !== void 0);
896
- if (textParts.length > 0) {
897
- result.push({ role: "user", content: textParts.map((p) => p.text).join("\n") });
923
+ const hasMedia = parts.some((p) => p.inlineData || p.fileData);
924
+ if (hasMedia) {
925
+ const content = parts.filter((p) => p.text !== void 0 || p.inlineData || p.fileData).map((p) => {
926
+ if (p.text !== void 0) return { type: "text", text: p.text };
927
+ const imageUrl = geminiMediaImageUrl(p);
928
+ return imageUrl ? { type: "image_url", image_url: imageUrl } : null;
929
+ }).filter((p) => p !== null);
930
+ if (content.length > 0) {
931
+ result.push({ role: "user", content });
932
+ }
933
+ } else {
934
+ const textParts = parts.filter((p) => p.text !== void 0);
935
+ if (textParts.length > 0) {
936
+ result.push({ role: "user", content: textParts.map((p) => p.text).join("\n") });
937
+ }
898
938
  }
899
939
  for (const fr of funcResponses) {
900
940
  result.push({
@@ -934,6 +974,15 @@ function openAIToGemini(messages) {
934
974
  continue;
935
975
  }
936
976
  if (msg.role === "user") {
977
+ if (Array.isArray(msg.content) && msg.content.some((p) => p.type === "image_url")) {
978
+ const geminiParts = msg.content.map((p) => {
979
+ if (p.type === "text") return { text: p.text };
980
+ if (p.type === "image_url") return geminiMediaPart(p.image_url);
981
+ return null;
982
+ }).filter((p) => p !== null);
983
+ result.push({ role: "user", parts: geminiParts });
984
+ continue;
985
+ }
937
986
  const text = typeof msg.content === "string" ? msg.content : (msg.content ?? []).filter((p) => p.type === "text").map((p) => p.text).join("\n");
938
987
  result.push({ role: "user", parts: [{ text }] });
939
988
  continue;
@@ -1100,6 +1149,6 @@ async function compress(messages, options = {}) {
1100
1149
  return finalResult;
1101
1150
  }
1102
1151
 
1103
- export { CacheError, CompressionHooks, ConfigurationError, HeadroomAuthError, HeadroomClient, HeadroomCompressError, HeadroomConnectionError, HeadroomError, ProviderError, StorageError, TokenizationError, TransformError, ValidationError, __require, camelToSnake, collectStream, compress, countTurns, deepCamelCase, deepSnakeCase, detectFormat, extractToolCalls, extractUserQuery, fromOpenAI, mapProxyError, openAIToVercel, parseSSE, snakeToCamel, toOpenAI, vercelToOpenAI };
1104
- //# sourceMappingURL=chunk-24W6JPRV.js.map
1105
- //# sourceMappingURL=chunk-24W6JPRV.js.map
1152
+ export { CacheError, CompressionHooks, ConfigurationError, HeadroomAuthError, HeadroomClient, HeadroomCompressError, HeadroomConnectionError, HeadroomError, ProviderError, StorageError, TokenizationError, TransformError, ValidationError, __require, anthropicToOpenAI, camelToSnake, collectStream, compress, countTurns, deepCamelCase, deepSnakeCase, detectFormat, extractToolCalls, extractUserQuery, fromOpenAI, mapProxyError, openAIToAnthropic, openAIToVercel, parseSSE, snakeToCamel, toOpenAI, vercelToOpenAI };
1153
+ //# sourceMappingURL=chunk-FJQ65W3R.js.map
1154
+ //# sourceMappingURL=chunk-FJQ65W3R.js.map