codex-copilot-dx 0.4.19 → 0.4.20
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 +3 -3
- package/package.json +1 -5
- package/src/anthropic.mjs +14 -3
- package/src/copilot.mjs +19 -3
package/README.md
CHANGED
|
@@ -93,8 +93,8 @@ Environment variables:
|
|
|
93
93
|
| `CCDX_UPSTREAM_RETRY_DELAY_MS` | `300` | Initial upstream retry backoff in milliseconds; capped at `5000` |
|
|
94
94
|
| `CCDX_LOG_PATH` | unset | Mirror terminal logs to a file; set to `1` for `~/.local/share/codex-copilot-dx/debug.log` |
|
|
95
95
|
| `CCDX_LOG_LEVEL` | `info` | Set to `debug` to include upstream request attempts, status codes, retry causes, and timings |
|
|
96
|
-
| `CCDX_IMG_MAX_DIM` | `2048` | Max long edge in pixels for image downscaling |
|
|
97
|
-
| `CCDX_IMG_QUALITY` | `85` | WebP quality used when re-encoding
|
|
96
|
+
| `CCDX_IMG_MAX_DIM` | `2048` | Max long edge in pixels for optional image downscaling |
|
|
97
|
+
| `CCDX_IMG_QUALITY` | `85` | WebP quality used when optional image re-encoding is available |
|
|
98
98
|
| `CCDX_IMG_MIN_BYTES` | `100000` | Images smaller than this are left untouched |
|
|
99
99
|
| `CCDX_IMG_CONCURRENCY` | `4` | Concurrent image optimization tasks; values above `12` are capped at `12` |
|
|
100
100
|
| `CCDX_DISABLE_IMG_OPT` | unset | Set to `1` to disable image optimization |
|
|
@@ -127,7 +127,7 @@ codex-copilot-dx usage
|
|
|
127
127
|
|
|
128
128
|
Long computer-use sessions can accumulate screenshots inside the conversation history. Each screenshot is shipped on later turns, and GitHub Copilot's `/responses` endpoint can reject oversized requests with `413 Payload Too Large`.
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
When the optional `sharp` package is available, the adapter downsamples embedded screenshots to long-edge <= 2048 px and re-encodes them as WebP before forwarding `/v1/responses`. `sharp` is not installed by default so the CLI stays lightweight and avoids native package install stalls; install it alongside `codex-copilot-dx` if you want this optimization.
|
|
131
131
|
|
|
132
132
|
## License
|
|
133
133
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codex-copilot-dx",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.20",
|
|
4
4
|
"description": "Use Codex Desktop, Claude Code, and Claude App with GitHub Copilot",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -27,9 +27,5 @@
|
|
|
27
27
|
"license": "MIT",
|
|
28
28
|
"scripts": {
|
|
29
29
|
"test": "node --test"
|
|
30
|
-
},
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"gpt-tokenizer": "^3.4.0",
|
|
33
|
-
"sharp": "^0.34.5"
|
|
34
30
|
}
|
|
35
31
|
}
|
package/src/anthropic.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import { encode } from "gpt-tokenizer";
|
|
3
2
|
|
|
4
3
|
// Anthropic Messages API to OpenAI chat/completions translation.
|
|
5
4
|
// Pure functions only; network calls stay in adapter.mjs and copilot.mjs.
|
|
@@ -238,7 +237,19 @@ export async function streamAnthropicFromLines(lineIterator, emit, model, option
|
|
|
238
237
|
await emit("message_stop", { type: "message_stop" });
|
|
239
238
|
}
|
|
240
239
|
|
|
241
|
-
|
|
240
|
+
function estimateTokens(text) {
|
|
241
|
+
if (!text) return 0;
|
|
242
|
+
let asciiChars = 0;
|
|
243
|
+
let nonAsciiChars = 0;
|
|
244
|
+
for (const ch of text) {
|
|
245
|
+
if (/\s/.test(ch)) continue;
|
|
246
|
+
if (ch.codePointAt(0) <= 0x7f) asciiChars += 1;
|
|
247
|
+
else nonAsciiChars += 1;
|
|
248
|
+
}
|
|
249
|
+
return Math.max(1, Math.ceil(asciiChars / 4) + nonAsciiChars);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Copilot has no count_tokens endpoint; estimate locally without install-time dependencies.
|
|
242
253
|
export function countTokens(body) {
|
|
243
254
|
const parts = [];
|
|
244
255
|
const sys = systemToText(body.system);
|
|
@@ -263,5 +274,5 @@ export function countTokens(body) {
|
|
|
263
274
|
}
|
|
264
275
|
|
|
265
276
|
const text = parts.join("\n");
|
|
266
|
-
return { input_tokens:
|
|
277
|
+
return { input_tokens: estimateTokens(text) };
|
|
267
278
|
}
|
package/src/copilot.mjs
CHANGED
|
@@ -21,6 +21,8 @@ const IMG_CONCURRENCY = parseImageConcurrency(process.env.CCDX_IMG_CONCURRENCY);
|
|
|
21
21
|
const UPSTREAM_RETRIES = parseUpstreamRetries(process.env.CCDX_UPSTREAM_RETRIES);
|
|
22
22
|
const UPSTREAM_RETRY_DELAY_MS = parseUpstreamRetryDelayMs(process.env.CCDX_UPSTREAM_RETRY_DELAY_MS);
|
|
23
23
|
let sharpImport = null;
|
|
24
|
+
let sharpUnavailable = false;
|
|
25
|
+
let sharpUnavailableLogged = false;
|
|
24
26
|
|
|
25
27
|
export function parseImageConcurrency(value) {
|
|
26
28
|
const n = Number.parseInt(value, 10);
|
|
@@ -173,9 +175,16 @@ export async function fetchCopilotUpstream(
|
|
|
173
175
|
}
|
|
174
176
|
|
|
175
177
|
async function sharp() {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
178
|
+
if (sharpUnavailable) return null;
|
|
179
|
+
try {
|
|
180
|
+
sharpImport ||= import("sharp");
|
|
181
|
+
const mod = await sharpImport;
|
|
182
|
+
return mod.default || mod;
|
|
183
|
+
} catch {
|
|
184
|
+
sharpUnavailable = true;
|
|
185
|
+
sharpImport = null;
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
179
188
|
}
|
|
180
189
|
|
|
181
190
|
export async function optimizeImageDataUrl(dataUrl) {
|
|
@@ -189,6 +198,13 @@ export async function optimizeImageDataUrl(dataUrl) {
|
|
|
189
198
|
|
|
190
199
|
try {
|
|
191
200
|
const resize = await sharp();
|
|
201
|
+
if (!resize) {
|
|
202
|
+
if (!sharpUnavailableLogged) {
|
|
203
|
+
sharpUnavailableLogged = true;
|
|
204
|
+
console.warn(status("warn", "image optimization skipped because optional dependency sharp is not installed"));
|
|
205
|
+
}
|
|
206
|
+
return dataUrl;
|
|
207
|
+
}
|
|
192
208
|
const out = await resize(raw, { failOn: "none" })
|
|
193
209
|
.rotate()
|
|
194
210
|
.resize(IMG_MAX_DIM, IMG_MAX_DIM, { fit: "inside", withoutEnlargement: true })
|