@sliday/tamp 0.2.4 → 0.2.6

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Tamp
2
2
 
3
- **Token compression proxy for coding agents.** 33.9% fewer input tokens, zero code changes. Works with Claude Code, Aider, Cursor, Cline, Windsurf, and any OpenAI-compatible agent.
3
+ **Token compression proxy for coding agents.** 33.9% fewer input tokens, zero code changes. Works with Claude Code, Codex, Aider, Cursor, Cline, Windsurf, and any OpenAI-compatible agent.
4
4
 
5
5
  ```
6
6
  npx @sliday/tamp
@@ -19,6 +19,7 @@ Tamp auto-detects your agent's API format and compresses tool result blocks befo
19
19
  ```
20
20
  Claude Code ──► Tamp (localhost:7778) ──► Anthropic API
21
21
  Aider/Cursor ──► │ ──► OpenAI API
22
+ Codex CLI ─────► │ ──► OpenAI API
22
23
  Gemini CLI ────► │ ──► Google AI API
23
24
 
24
25
  ├─ JSON → minify whitespace
@@ -34,6 +35,7 @@ Gemini CLI ────► │ ──► Google AI API
34
35
  |--------|----------|--------|
35
36
  | Anthropic Messages | `POST /v1/messages` | Claude Code |
36
37
  | OpenAI Chat Completions | `POST /v1/chat/completions` | Aider, Cursor, Cline, Windsurf, OpenCode |
38
+ | OpenAI Responses | `POST /v1/responses` | Codex CLI |
37
39
  | Google Gemini | `POST .../generateContent` | Gemini CLI |
38
40
 
39
41
  ### Compression Stages
@@ -81,6 +83,12 @@ export OPENAI_API_BASE=http://localhost:7778
81
83
  aider
82
84
  ```
83
85
 
86
+ **Codex CLI:**
87
+ Add to `~/.codex/config.toml`:
88
+ ```toml
89
+ openai_base_url = "http://localhost:7778"
90
+ ```
91
+
84
92
  **Cursor / Cline / Windsurf:**
85
93
  Set the API base URL to `http://localhost:7778` in your editor's settings.
86
94
 
@@ -96,7 +104,7 @@ All configuration via environment variables:
96
104
  | `TAMP_UPSTREAM` | `https://api.anthropic.com` | Default upstream API URL |
97
105
  | `TAMP_UPSTREAM_OPENAI` | `https://api.openai.com` | Upstream for OpenAI-format requests |
98
106
  | `TAMP_UPSTREAM_GEMINI` | `https://generativelanguage.googleapis.com` | Upstream for Gemini-format requests |
99
- | `TAMP_STAGES` | `minify` | Comma-separated compression stages |
107
+ | `TAMP_STAGES` | `minify,toon` | Comma-separated compression stages |
100
108
  | `TAMP_MIN_SIZE` | `200` | Minimum content size (chars) to attempt compression |
101
109
  | `TAMP_LOG` | `true` | Enable request logging to stderr |
102
110
  | `TAMP_LOG_FILE` | _(none)_ | Write logs to file |
package/bin/tamp.js CHANGED
@@ -1,12 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { createProxy } from '../index.js'
3
- import { existsSync } from 'node:fs'
3
+ import { existsSync, readFileSync } from 'node:fs'
4
4
  import { spawn } from 'node:child_process'
5
5
  import { fileURLToPath } from 'node:url'
6
6
  import { dirname, join } from 'node:path'
7
7
 
8
8
  const __dirname = dirname(fileURLToPath(import.meta.url))
9
9
  const root = join(__dirname, '..')
10
+ const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf-8'))
10
11
 
11
12
  // ANSI colors
12
13
  const c = {
@@ -28,7 +29,7 @@ function printBanner(config) {
28
29
  const url = `http://localhost:${config.port}`
29
30
 
30
31
  log('')
31
- log(` ${c.bold}${c.cyan}┌─ Tamp ─────────────────────────────────┐${c.reset}`)
32
+ log(` ${c.bold}${c.cyan}┌─ Tamp ${c.dim}v${pkg.version}${c.reset}${c.bold}${c.cyan} ───────────────────────────────┐${c.reset}`)
32
33
  log(` ${c.cyan}│${c.reset} Proxy: ${c.bold}${c.green}${url}${c.reset}${c.cyan} │${c.reset}`)
33
34
  log(` ${c.cyan}│${c.reset} Status: ${c.bgGreen}${c.bold} ● READY ${c.reset}${c.cyan} │${c.reset}`)
34
35
  log(` ${c.cyan}│${c.reset} ${c.cyan}│${c.reset}`)
package/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  import http from 'node:http'
2
2
  import https from 'node:https'
3
+ import zlib from 'node:zlib'
4
+ import * as fzstd from 'fzstd'
3
5
  import { loadConfig } from './config.js'
4
6
  import { compressRequest } from './compress.js'
5
7
  import { detectProvider } from './providers.js'
@@ -138,10 +140,44 @@ return http.createServer(async (req, res) => {
138
140
  const headers = { ...req.headers }
139
141
  delete headers.host
140
142
 
143
+ // Decompress request body if content-encoding is set
144
+ const encoding = (req.headers['content-encoding'] || '').toLowerCase()
145
+ let textBody
146
+ let decompressed = false
141
147
  try {
142
- const parsed = JSON.parse(rawBody.toString('utf-8'))
148
+ if (encoding === 'gzip') {
149
+ textBody = zlib.gunzipSync(rawBody)
150
+ decompressed = true
151
+ } else if (encoding === 'deflate') {
152
+ textBody = zlib.inflateSync(rawBody)
153
+ decompressed = true
154
+ } else if (encoding === 'br') {
155
+ textBody = zlib.brotliDecompressSync(rawBody)
156
+ decompressed = true
157
+ } else if (encoding === 'zstd') {
158
+ textBody = Buffer.from(fzstd.decompress(new Uint8Array(rawBody)))
159
+ decompressed = true
160
+ } else if (encoding && encoding !== 'identity') {
161
+ // Unknown encoding — can't decompress, passthrough as-is
162
+ if (config.log) console.error(`[tamp] passthrough (unsupported encoding: ${encoding})`)
163
+ forwardRequest(req.method, upstreamUrl, headers, rawBody, res)
164
+ return
165
+ } else {
166
+ textBody = rawBody
167
+ }
168
+ } catch {
169
+ // Decompression failed — passthrough original body
170
+ if (config.log) console.error(`[tamp] passthrough (decompression failed)`)
171
+ forwardRequest(req.method, upstreamUrl, headers, rawBody, res)
172
+ return
173
+ }
174
+
175
+ try {
176
+ const parsed = JSON.parse(textBody.toString('utf-8'))
143
177
  const { body, stats } = await compressRequest(parsed, config, provider)
144
178
  finalBody = Buffer.from(JSON.stringify(body), 'utf-8')
179
+ // Send uncompressed — simpler and content-length is accurate
180
+ if (decompressed) delete headers['content-encoding']
145
181
 
146
182
  if (config.log && stats.length) {
147
183
  session.record(stats)
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "providers.js",
10
10
  "stats.js"
11
11
  ],
12
- "version": "0.2.4",
12
+ "version": "0.2.6",
13
13
  "description": "Token compression proxy for coding agents. Works with Claude Code, Aider, Cursor, Cline, Windsurf. 33.9% fewer input tokens.",
14
14
  "type": "module",
15
15
  "main": "index.js",
@@ -39,6 +39,7 @@
39
39
  "homepage": "https://github.com/sliday/tamp",
40
40
  "dependencies": {
41
41
  "@anthropic-ai/tokenizer": "^0.0.4",
42
- "@toon-format/toon": "^2.1.0"
42
+ "@toon-format/toon": "^2.1.0",
43
+ "fzstd": "^0.1.1"
43
44
  }
44
45
  }