dsh-lcx-codex 0.3.1 → 0.3.2
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/CHANGELOG.md +7 -0
- package/README.md +1 -1
- package/README_EN.md +1 -1
- package/lib/compact-v2.js +4 -2
- package/lib/index.js +33 -10
- package/package.json +1 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.3.2 - 2026-08-21
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Native V2 compact 与同路由 replay 现在和 DSH/Pi 普通 Responses 请求复用相同的 session `prompt_cache_key`、缓存 retention 与会话 header,避免压缩边界额外切换 NewAPI/Sub2API 的缓存和账号粘性域;`cacheRetention: none` 时同时省略这些缓存信号。
|
|
12
|
+
- 移除未被插件直接导入或注入的 `@deepseek-ai/dsh-compaction-basic` peer 声明,避免 DSH/pnpm 安装时出现误导性的宿主依赖警告;Basic fallback 继续通过 DSH `llm/stream` 的 `next()` 链调用宿主实现。
|
|
13
|
+
|
|
7
14
|
## 0.3.1 - 2026-08-21
|
|
8
15
|
|
|
9
16
|
### Fixed
|
package/README.md
CHANGED
package/README_EN.md
CHANGED
|
@@ -78,7 +78,7 @@ dsh plugin --profile web add dsh-lcx-codex
|
|
|
78
78
|
You can also install a specific `.tgz` file from a GitHub Release:
|
|
79
79
|
|
|
80
80
|
```powershell
|
|
81
|
-
dsh plugin --profile web add .\dsh-lcx-codex-0.3.
|
|
81
|
+
dsh plugin --profile web add .\dsh-lcx-codex-0.3.2.tgz
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
Start DSH after installation:
|
package/lib/compact-v2.js
CHANGED
|
@@ -156,7 +156,7 @@ export function mergeFeatureHeader(headers) {
|
|
|
156
156
|
return result
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
export function buildNativeCompactionBody({ model, input, instructions, promptCacheKey, tools }) {
|
|
159
|
+
export function buildNativeCompactionBody({ model, input, instructions, promptCacheKey, promptCacheRetention, tools }) {
|
|
160
160
|
if (!Array.isArray(input)) throw protocolError('Native compaction input must be an array', 'LCX_COMPACT_INVALID_INPUT')
|
|
161
161
|
if (input.some((item) => isObject(item) && item.type === 'compaction_trigger')) {
|
|
162
162
|
throw protocolError('Native compaction input already contains compaction_trigger', 'LCX_COMPACT_DUPLICATE_TRIGGER')
|
|
@@ -170,6 +170,7 @@ export function buildNativeCompactionBody({ model, input, instructions, promptCa
|
|
|
170
170
|
...(nativeTools !== undefined ? { tools: nativeTools } : {}),
|
|
171
171
|
...(instructions !== undefined ? { instructions: structuredClone(instructions) } : {}),
|
|
172
172
|
...(promptCacheKey !== undefined && promptCacheKey !== null ? { prompt_cache_key: String(promptCacheKey) } : {}),
|
|
173
|
+
...(promptCacheRetention !== undefined && promptCacheRetention !== null ? { prompt_cache_retention: String(promptCacheRetention) } : {}),
|
|
173
174
|
}
|
|
174
175
|
}
|
|
175
176
|
|
|
@@ -273,6 +274,7 @@ export async function requestNativeCompaction({
|
|
|
273
274
|
input,
|
|
274
275
|
instructions,
|
|
275
276
|
promptCacheKey,
|
|
277
|
+
promptCacheRetention,
|
|
276
278
|
idempotencyKey,
|
|
277
279
|
tools,
|
|
278
280
|
headers,
|
|
@@ -281,7 +283,7 @@ export async function requestNativeCompaction({
|
|
|
281
283
|
maxAttempts,
|
|
282
284
|
maxResponseBytes,
|
|
283
285
|
}) {
|
|
284
|
-
const body = buildNativeCompactionBody({ model, input, instructions, promptCacheKey, tools })
|
|
286
|
+
const body = buildNativeCompactionBody({ model, input, instructions, promptCacheKey, promptCacheRetention, tools })
|
|
285
287
|
const requestHeaders = { ...(headers ?? {}) }
|
|
286
288
|
if (idempotencyKey !== undefined && idempotencyKey !== null && !Object.keys(requestHeaders).some((name) => name.toLowerCase() === 'idempotency-key')) {
|
|
287
289
|
requestHeaders['idempotency-key'] = String(idempotencyKey)
|
package/lib/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import z from '@deepseek-ai/schemastery'
|
|
2
2
|
import { attributionHeaders, resolveRetryPolicy } from '@deepseek-ai/dsh-llm'
|
|
3
3
|
import { settingsNamespace } from '@deepseek-ai/dsh-settings'
|
|
4
|
+
import { clampOpenAIPromptCacheKey } from '@earendil-works/pi-ai/api/openai-prompt-cache'
|
|
4
5
|
import { randomUUID } from 'node:crypto'
|
|
5
6
|
import { homedir } from 'node:os'
|
|
6
7
|
import { join } from 'node:path'
|
|
@@ -135,6 +136,7 @@ function normalizeCompactTransport(value) {
|
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
function normalizeConfig(input = {}) {
|
|
139
|
+
const cacheRetention = ['none', 'short', 'long'].includes(input.cacheRetention) ? input.cacheRetention : 'short'
|
|
138
140
|
return {
|
|
139
141
|
provider: input.provider || 'lcx',
|
|
140
142
|
baseURL: String(input.baseURL || 'https://api.lcxbot.com/v1').replace(/\/+$/u, ''),
|
|
@@ -142,6 +144,8 @@ function normalizeConfig(input = {}) {
|
|
|
142
144
|
model: input.model || 'gpt-5.6-sol',
|
|
143
145
|
compactTransport: normalizeCompactTransport(input.compactTransport),
|
|
144
146
|
headers: input.headers && typeof input.headers === 'object' ? { ...input.headers } : {},
|
|
147
|
+
cacheRetention,
|
|
148
|
+
supportsLongCacheRetention: input.supportsLongCacheRetention !== false,
|
|
145
149
|
checkpointPath: input.checkpointPath || defaultCheckpointPath(),
|
|
146
150
|
portableCheckpointPath: input.portableCheckpointPath || portableCheckpointPath(input.checkpointPath || defaultCheckpointPath()),
|
|
147
151
|
alphaCapabilityPath: input.alphaCapabilityPath || defaultAlphaCapabilityPath(),
|
|
@@ -186,6 +190,8 @@ function resolveResponsesRouteConfig(ctx, options, fallbackConfig) {
|
|
|
186
190
|
baseURL,
|
|
187
191
|
apiKeyEnv,
|
|
188
192
|
headers: profile.headers ?? fallbackConfig.headers,
|
|
193
|
+
cacheRetention: profile.cacheRetention ?? fallbackConfig.cacheRetention,
|
|
194
|
+
supportsLongCacheRetention: profile.compat?.supportsLongCacheRetention ?? fallbackConfig.supportsLongCacheRetention,
|
|
189
195
|
model: options.model,
|
|
190
196
|
compactTransport: profile.compactTransport ?? fallbackConfig.compactTransport,
|
|
191
197
|
timeoutMs: profile.timeoutMs ?? fallbackConfig.timeoutMs,
|
|
@@ -301,7 +307,7 @@ async function authenticatedHeaders(ctx, config, sessionId, clientRequestId) {
|
|
|
301
307
|
...config.headers,
|
|
302
308
|
...attributionHeaders(),
|
|
303
309
|
authorization: `Bearer ${await resolveApiKey(ctx, config)}`,
|
|
304
|
-
'x-client-request-id': clientRequestId ?? randomUUID(),
|
|
310
|
+
...(clientRequestId === null ? {} : { 'x-client-request-id': clientRequestId ?? (sessionId ? String(sessionId) : randomUUID()) }),
|
|
305
311
|
...(sessionId ? { 'session-id': String(sessionId) } : {}),
|
|
306
312
|
}
|
|
307
313
|
}
|
|
@@ -361,19 +367,35 @@ function routeWithSessionAncestry(ctx, route) {
|
|
|
361
367
|
return { ...route, ancestorSessionIds: sessionAncestry(ctx, route.sessionId) }
|
|
362
368
|
}
|
|
363
369
|
|
|
364
|
-
function
|
|
365
|
-
|
|
370
|
+
function promptCacheSessionId(route, config) {
|
|
371
|
+
if (config?.cacheRetention === 'none') return undefined
|
|
372
|
+
return route?.sessionId ? String(route.sessionId) : undefined
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function promptCacheKey(route, config) {
|
|
376
|
+
const sessionId = promptCacheSessionId(route, config)
|
|
377
|
+
return sessionId ? clampOpenAIPromptCacheKey(sessionId) : undefined
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function promptCacheRetention(config) {
|
|
381
|
+
return config?.cacheRetention === 'long' && config.supportsLongCacheRetention !== false ? '24h' : undefined
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
function promptCacheHeaders(ctx, config, route) {
|
|
385
|
+
const sessionId = promptCacheSessionId(route, config)
|
|
386
|
+
return authenticatedHeaders(ctx, config, sessionId, sessionId === undefined ? null : undefined)
|
|
366
387
|
}
|
|
367
388
|
|
|
368
389
|
async function requestRemoteCompaction(options, input, config, signal, ctx, route, preflightHeaders) {
|
|
369
390
|
try {
|
|
370
|
-
const headers = preflightHeaders ?? await
|
|
391
|
+
const headers = preflightHeaders ?? await promptCacheHeaders(ctx, config, route)
|
|
371
392
|
return await requestNativeCompaction({
|
|
372
393
|
baseURL: config.baseURL,
|
|
373
394
|
model: options.model,
|
|
374
395
|
input,
|
|
375
396
|
instructions: options.system,
|
|
376
|
-
promptCacheKey: promptCacheKey(route),
|
|
397
|
+
promptCacheKey: promptCacheKey(route, config),
|
|
398
|
+
promptCacheRetention: promptCacheRetention(config),
|
|
377
399
|
idempotencyKey: randomUUID(),
|
|
378
400
|
tools: options.tools,
|
|
379
401
|
headers,
|
|
@@ -731,7 +753,7 @@ function checkpointReplayRecord(messages, store) {
|
|
|
731
753
|
return { marker, record }
|
|
732
754
|
}
|
|
733
755
|
|
|
734
|
-
function nativeReplayBody(options, route, nativeOutput, tailInput) {
|
|
756
|
+
function nativeReplayBody(options, route, config, nativeOutput, tailInput) {
|
|
735
757
|
return {
|
|
736
758
|
model: options.model,
|
|
737
759
|
input: [...structuredClone(nativeOutput), ...structuredClone(tailInput)],
|
|
@@ -739,7 +761,8 @@ function nativeReplayBody(options, route, nativeOutput, tailInput) {
|
|
|
739
761
|
store: false,
|
|
740
762
|
...(options.tools !== undefined ? { tools: responsesTools(options.tools) } : {}),
|
|
741
763
|
...(options.system !== undefined ? { instructions: options.system } : {}),
|
|
742
|
-
...(promptCacheKey(route) ? { prompt_cache_key: promptCacheKey(route) } : {}),
|
|
764
|
+
...(promptCacheKey(route, config) ? { prompt_cache_key: promptCacheKey(route, config) } : {}),
|
|
765
|
+
...(promptCacheRetention(config) ? { prompt_cache_retention: promptCacheRetention(config) } : {}),
|
|
743
766
|
}
|
|
744
767
|
}
|
|
745
768
|
|
|
@@ -762,8 +785,8 @@ async function* nativeCheckpointReplayStream(options, config, portableStore, ctx
|
|
|
762
785
|
try {
|
|
763
786
|
const response = await fetchSse(
|
|
764
787
|
`${config.baseURL}/responses`,
|
|
765
|
-
nativeReplayBody(options, route, nativeOutput, tailInput),
|
|
766
|
-
mergeFeatureHeader(await
|
|
788
|
+
nativeReplayBody(options, route, config, nativeOutput, tailInput),
|
|
789
|
+
mergeFeatureHeader(await promptCacheHeaders(ctx, config, route)),
|
|
767
790
|
replaySignals.signal,
|
|
768
791
|
config.timeoutMs + 1000,
|
|
769
792
|
{ maxResponseBytes: config.maxResponseBytes },
|
|
@@ -822,7 +845,7 @@ async function prepareRemoteCompaction(options, config, portableStore, ctx, sess
|
|
|
822
845
|
const route = currentRoute(options, config)
|
|
823
846
|
const lease = sessionTracker?.capture(route.sessionId)
|
|
824
847
|
lease?.assert('request-start')
|
|
825
|
-
const headers = await
|
|
848
|
+
const headers = await promptCacheHeaders(ctx, config, route)
|
|
826
849
|
responsesTools(options.tools)
|
|
827
850
|
const llm = ctx?.llm ?? ctx?.get?.('llm')
|
|
828
851
|
const imageSupport = typeof llm?.resolveModelInfo === 'function'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-lcx-codex",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "DSH web search and Responses native V2 compaction for Sub2API-proxied or NewAPI-relayed GPT models",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -62,7 +62,6 @@
|
|
|
62
62
|
"@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8",
|
|
63
63
|
"@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8",
|
|
64
64
|
"@deepseek-ai/dsh-client-ui-slots": "^0.1.0-rc.8",
|
|
65
|
-
"@deepseek-ai/dsh-compaction-basic": "^0.1.0-rc.8",
|
|
66
65
|
"@deepseek-ai/dsh-credentials": "^0.1.0-rc.8",
|
|
67
66
|
"@deepseek-ai/dsh-llm": "^0.1.0-rc.8",
|
|
68
67
|
"@deepseek-ai/dsh-settings": "^0.1.0-rc.8",
|