dsh-lcx-codex 0.3.1 → 0.3.3

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 CHANGED
@@ -4,6 +4,24 @@
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.3.3 - 2026-08-21
8
+
9
+ ### Fixed
10
+
11
+ - Native V2 checkpoint 现在由客户端按 64K token 预算保留最近真实 user messages,再追加 exactly-one compaction item;不再错误假设上游 `response.output` 会返回 retained messages。旧的 compaction-only v3 checkpoint 会从 portable history 安全补全,运行时上下文注入不会进入 replacement history。
12
+
13
+ ### Documentation
14
+
15
+ - 记录 installed `0.3.2` 的 compact + 三次 replay 缓存实测,并说明 Sub2API Codex OAuth 路径会删除上游不支持的 `prompt_cache_retention`;短缓存过期后的单次冷请求不等于插件改变了稳定前缀。
16
+ - 增加连续 replay 的前缀稳定性回归断言,区分缓存生命周期与 replacement-history 保真问题。
17
+
18
+ ## 0.3.2 - 2026-08-21
19
+
20
+ ### Fixed
21
+
22
+ - Native V2 compact 与同路由 replay 现在和 DSH/Pi 普通 Responses 请求复用相同的 session `prompt_cache_key`、缓存 retention 与会话 header,避免压缩边界额外切换 NewAPI/Sub2API 的缓存和账号粘性域;`cacheRetention: none` 时同时省略这些缓存信号。
23
+ - 移除未被插件直接导入或注入的 `@deepseek-ai/dsh-compaction-basic` peer 声明,避免 DSH/pnpm 安装时出现误导性的宿主依赖警告;Basic fallback 继续通过 DSH `llm/stream` 的 `next()` 链调用宿主实现。
24
+
7
25
  ## 0.3.1 - 2026-08-21
8
26
 
9
27
  ### Fixed
package/README.md CHANGED
@@ -78,7 +78,7 @@ dsh plugin --profile web add dsh-lcx-codex
78
78
  也可以下载 GitHub Release 中的 `.tgz` 安装指定版本:
79
79
 
80
80
  ```powershell
81
- dsh plugin --profile web add .\dsh-lcx-codex-0.3.1.tgz
81
+ dsh plugin --profile web add .\dsh-lcx-codex-0.3.2.tgz
82
82
  ```
83
83
 
84
84
  安装后启动 DSH:
@@ -130,6 +130,8 @@ node (Join-Path $dshHome 'profiles\web\node_modules\dsh-lcx-codex\scripts\probe-
130
130
  - Alpha capability:`$DSH_HOME/storages/lcx-codex/web-alpha-capabilities.json`
131
131
  - Alpha refs:`$DSH_HOME/storages/lcx-codex/web-alpha-refs.json`
132
132
  - 只支持 Native remote-compaction V2,不调用 `/responses/compact`
133
+ - 同路由 replay 会复用 DSH session 的 `prompt_cache_key` 并保持已有请求前缀稳定;短期缓存过期后仍可能出现单次冷请求,不能用会话累计命中率判断插件是否破坏缓存
134
+ - Sub2API 的 Codex OAuth 转换层会删除上游不支持的 `prompt_cache_retention`,因此经该路径设置 `24h` 不会延长缓存;以实际连续请求的 `cached_tokens` 为准
133
135
  - Checkpoint 不保存图片原始字节或 data URL
134
136
  - Opaque checkpoint 不跨不兼容 provider、model、base URL、session 或 lineage 回放
135
137
  - 不包含图片生成功能
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.1.tgz
81
+ dsh plugin --profile web add .\dsh-lcx-codex-0.3.2.tgz
82
82
  ```
83
83
 
84
84
  Start DSH after installation:
@@ -130,6 +130,8 @@ The probe does not print the key or full response bodies. Restart DSH, or disabl
130
130
  - Alpha capabilities: `$DSH_HOME/storages/lcx-codex/web-alpha-capabilities.json`
131
131
  - Alpha references: `$DSH_HOME/storages/lcx-codex/web-alpha-refs.json`
132
132
  - Only Native remote-compaction V2 is supported; `/responses/compact` is never called.
133
+ - Same-route replay reuses the DSH session `prompt_cache_key` and preserves the existing request prefix. A single cold request can still occur after the short-lived upstream cache expires, so the cumulative session hit rate is not evidence that the plugin changed the prefix.
134
+ - Sub2API strips the unsupported `prompt_cache_retention` field on its Codex OAuth path, so requesting `24h` does not extend cache lifetime on that route. Use the `cached_tokens` reported by consecutive real requests as the authoritative signal.
133
135
  - Checkpoints never store raw image bytes or data URLs.
134
136
  - Opaque checkpoints are not replayed across an incompatible provider, model, base URL, session, or lineage.
135
137
  - Image generation is not included.
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/compact.js CHANGED
@@ -4,8 +4,107 @@ import { offloadDshRequestImages, resolveDshImage, serializeDshResponsesInput }
4
4
  const UNSUPPORTED_CHECKPOINT_PATTERN = /\[dsh-lcx-codex-checkpoint:[0-9a-f-]{36}\]/iu
5
5
  const PORTABLE_CHECKPOINT_PATTERN = /\[dsh-lcx-codex-v3-checkpoint:([0-9a-f-]{36})\]/giu
6
6
  const PORTABLE_HISTORY_TOKEN_BUDGET = 20_000
7
+ export const NATIVE_RETAINED_MESSAGE_TOKEN_BUDGET = 64_000
7
8
  export const PORTABLE_HISTORY_BYTE_BUDGET = 2 * 1024 * 1024
8
9
  const UNSUPPORTED_IMAGE_PLACEHOLDER = '[image omitted because the target model does not support image input]'
10
+ const NATIVE_IMAGE_TOKEN_ESTIMATE = 765
11
+ const CONTEXTUAL_USER_PREFIXES = [
12
+ '<environment_context>',
13
+ '<user_instructions>',
14
+ '<additional_context>',
15
+ '<skills',
16
+ '<token_budget>',
17
+ '<model_switch>',
18
+ ]
19
+
20
+ function nativeContentPartTokens(part) {
21
+ if (part?.type === 'input_image' || part?.type === 'dsh_image_attachment') return NATIVE_IMAGE_TOKEN_ESTIMATE
22
+ if (typeof part?.text === 'string') return Math.ceil(part.text.length / 4)
23
+ return Math.ceil(JSON.stringify(part ?? null).length / 4)
24
+ }
25
+
26
+ function nativeMessageTokens(item) {
27
+ return Math.max(1, (item?.content ?? []).reduce((total, part) => total + nativeContentPartTokens(part), 0))
28
+ }
29
+
30
+ function truncatedNativeText(text, maxTokens) {
31
+ const maxChars = maxTokens * 4
32
+ if (maxChars <= 0) return ''
33
+ if (text.length <= maxChars) return text
34
+ const omittedTokens = Math.max(1, Math.ceil((text.length - maxChars) / 4))
35
+ const marker = `[...${omittedTokens} tokens truncated...]`
36
+ if (maxChars <= marker.length + 2) return text.slice(-maxChars)
37
+ const sideChars = Math.max(1, Math.floor((maxChars - marker.length) / 2))
38
+ return `${text.slice(0, sideChars)}${marker}${text.slice(-sideChars)}`
39
+ }
40
+
41
+ function truncateNativeUserMessage(item, maxTokens) {
42
+ let remaining = maxTokens
43
+ const content = []
44
+ for (const part of item?.content ?? []) {
45
+ if (remaining <= 0) break
46
+ const tokens = Math.max(1, nativeContentPartTokens(part))
47
+ if (tokens <= remaining) {
48
+ content.push(structuredClone(part))
49
+ remaining -= tokens
50
+ continue
51
+ }
52
+ if (typeof part?.text === 'string') {
53
+ const text = truncatedNativeText(part.text, remaining)
54
+ if (text) content.push({ ...structuredClone(part), text })
55
+ }
56
+ remaining = 0
57
+ }
58
+ return content.length > 0 ? { ...structuredClone(item), content } : undefined
59
+ }
60
+
61
+ function isNativeRetainedUserMessage(item) {
62
+ if (item?.type !== 'message' || item.role !== 'user' || !Array.isArray(item.content)) return false
63
+ return !item.content.some((part) => {
64
+ if (part?.type !== 'input_text' || typeof part.text !== 'string') return false
65
+ const text = part.text.trimStart().toLowerCase()
66
+ return CONTEXTUAL_USER_PREFIXES.some((prefix) => text.startsWith(prefix))
67
+ })
68
+ }
69
+
70
+ export function buildNativeReplacementHistory(input, compaction, options = {}) {
71
+ if (compaction?.type !== 'compaction' || typeof compaction.encrypted_content !== 'string' || compaction.encrypted_content.length === 0) {
72
+ const error = new Error('LCX Native replacement history requires one non-empty compaction item')
73
+ error.code = 'LCX_COMPACT_INVALID_RESPONSE'
74
+ throw error
75
+ }
76
+ let remaining = options.tokenBudget ?? NATIVE_RETAINED_MESSAGE_TOKEN_BUDGET
77
+ if (!Number.isSafeInteger(remaining) || remaining <= 0) {
78
+ const error = new Error('LCX Native retained message token budget must be a positive integer')
79
+ error.code = 'LCX_COMPACT_INVALID_INPUT'
80
+ throw error
81
+ }
82
+ const retained = []
83
+ const candidates = (input ?? []).filter(isNativeRetainedUserMessage)
84
+ for (let index = candidates.length - 1; index >= 0 && remaining > 0; index -= 1) {
85
+ const item = candidates[index]
86
+ const tokens = nativeMessageTokens(item)
87
+ if (tokens <= remaining) {
88
+ retained.push(structuredClone(item))
89
+ remaining -= tokens
90
+ continue
91
+ }
92
+ const truncated = truncateNativeUserMessage(item, remaining)
93
+ if (truncated) retained.push(truncated)
94
+ remaining = 0
95
+ }
96
+ retained.reverse()
97
+ retained.push(structuredClone(compaction))
98
+ return retained
99
+ }
100
+
101
+ export function checkpointNativeReplacementHistory(record) {
102
+ const nativeOutput = Array.isArray(record?.nativeOutput) ? record.nativeOutput : []
103
+ if (nativeOutput.some(isNativeRetainedUserMessage)) return structuredClone(nativeOutput)
104
+ const compaction = nativeOutput.find((item) => item?.type === 'compaction') ?? record?.nativeCompaction
105
+ if (!compaction) return structuredClone(nativeOutput)
106
+ return buildNativeReplacementHistory(record?.portableHistory ?? [], compaction)
107
+ }
9
108
 
10
109
  export function portableCheckpointIds(text) {
11
110
  return [...String(text ?? '').matchAll(PORTABLE_CHECKPOINT_PATTERN)].map((match) => match[1].toLowerCase())
@@ -461,7 +560,7 @@ export function buildPortableResponsesInput(messages, store, route) {
461
560
  throw error
462
561
  }
463
562
  const prefix = state === 'native-compatible'
464
- ? record.nativeOutput
563
+ ? checkpointNativeReplacementHistory(record)
465
564
  : [...portableSummaryItem(record.portableSummary), ...buildPortableHistory(record.portableHistory)]
466
565
  const tail = normalInput((messages ?? []).slice(marker.index + 1), { strict: true })
467
566
  return [...structuredClone(prefix), ...tail]
@@ -513,7 +612,7 @@ export async function buildPortableResponsesInputWithImages(messages, store, rou
513
612
  }
514
613
  }
515
614
  const prefix = state === 'native-compatible'
516
- ? await hydrateNativeImageReferences(record.nativeOutput, options)
615
+ ? await hydrateNativeImageReferences(checkpointNativeReplacementHistory(record), options)
517
616
  : [...portableSummaryItem(record.portableSummary), ...portableHistory]
518
617
  const tail = state === 'native-compatible'
519
618
  ? await serializeDshResponsesInput(requestMessages.slice(marker.index + 1), { ...options, imageSupport, route })
package/lib/index.js CHANGED
@@ -1,12 +1,14 @@
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'
7
8
  import { CheckpointV3Store, CHECKPOINT_V3_VERSION } from './checkpoint-store-v3.js'
8
9
  import {
9
10
  baseURLFingerprint,
11
+ buildNativeReplacementHistory,
10
12
  buildPortableHistory,
11
13
  assertCheckpointRoute,
12
14
  buildPortableResponsesInput,
@@ -14,6 +16,7 @@ import {
14
16
  hasPortableCheckpoint,
15
17
  hydrateNativeImageReferences,
16
18
  inputImageCount,
19
+ checkpointNativeReplacementHistory,
17
20
  latestPortableMarker,
18
21
  normalizeCompactionResponse,
19
22
  persistNativeImageReferences,
@@ -135,6 +138,7 @@ function normalizeCompactTransport(value) {
135
138
  }
136
139
 
137
140
  function normalizeConfig(input = {}) {
141
+ const cacheRetention = ['none', 'short', 'long'].includes(input.cacheRetention) ? input.cacheRetention : 'short'
138
142
  return {
139
143
  provider: input.provider || 'lcx',
140
144
  baseURL: String(input.baseURL || 'https://api.lcxbot.com/v1').replace(/\/+$/u, ''),
@@ -142,6 +146,8 @@ function normalizeConfig(input = {}) {
142
146
  model: input.model || 'gpt-5.6-sol',
143
147
  compactTransport: normalizeCompactTransport(input.compactTransport),
144
148
  headers: input.headers && typeof input.headers === 'object' ? { ...input.headers } : {},
149
+ cacheRetention,
150
+ supportsLongCacheRetention: input.supportsLongCacheRetention !== false,
145
151
  checkpointPath: input.checkpointPath || defaultCheckpointPath(),
146
152
  portableCheckpointPath: input.portableCheckpointPath || portableCheckpointPath(input.checkpointPath || defaultCheckpointPath()),
147
153
  alphaCapabilityPath: input.alphaCapabilityPath || defaultAlphaCapabilityPath(),
@@ -186,6 +192,8 @@ function resolveResponsesRouteConfig(ctx, options, fallbackConfig) {
186
192
  baseURL,
187
193
  apiKeyEnv,
188
194
  headers: profile.headers ?? fallbackConfig.headers,
195
+ cacheRetention: profile.cacheRetention ?? fallbackConfig.cacheRetention,
196
+ supportsLongCacheRetention: profile.compat?.supportsLongCacheRetention ?? fallbackConfig.supportsLongCacheRetention,
189
197
  model: options.model,
190
198
  compactTransport: profile.compactTransport ?? fallbackConfig.compactTransport,
191
199
  timeoutMs: profile.timeoutMs ?? fallbackConfig.timeoutMs,
@@ -301,7 +309,7 @@ async function authenticatedHeaders(ctx, config, sessionId, clientRequestId) {
301
309
  ...config.headers,
302
310
  ...attributionHeaders(),
303
311
  authorization: `Bearer ${await resolveApiKey(ctx, config)}`,
304
- 'x-client-request-id': clientRequestId ?? randomUUID(),
312
+ ...(clientRequestId === null ? {} : { 'x-client-request-id': clientRequestId ?? (sessionId ? String(sessionId) : randomUUID()) }),
305
313
  ...(sessionId ? { 'session-id': String(sessionId) } : {}),
306
314
  }
307
315
  }
@@ -361,19 +369,35 @@ function routeWithSessionAncestry(ctx, route) {
361
369
  return { ...route, ancestorSessionIds: sessionAncestry(ctx, route.sessionId) }
362
370
  }
363
371
 
364
- function promptCacheKey(route) {
365
- return route?.sessionId ? routeFingerprint(route) : undefined
372
+ function promptCacheSessionId(route, config) {
373
+ if (config?.cacheRetention === 'none') return undefined
374
+ return route?.sessionId ? String(route.sessionId) : undefined
375
+ }
376
+
377
+ function promptCacheKey(route, config) {
378
+ const sessionId = promptCacheSessionId(route, config)
379
+ return sessionId ? clampOpenAIPromptCacheKey(sessionId) : undefined
380
+ }
381
+
382
+ function promptCacheRetention(config) {
383
+ return config?.cacheRetention === 'long' && config.supportsLongCacheRetention !== false ? '24h' : undefined
384
+ }
385
+
386
+ function promptCacheHeaders(ctx, config, route) {
387
+ const sessionId = promptCacheSessionId(route, config)
388
+ return authenticatedHeaders(ctx, config, sessionId, sessionId === undefined ? null : undefined)
366
389
  }
367
390
 
368
391
  async function requestRemoteCompaction(options, input, config, signal, ctx, route, preflightHeaders) {
369
392
  try {
370
- const headers = preflightHeaders ?? await authenticatedHeaders(ctx, config, options.sessionId)
393
+ const headers = preflightHeaders ?? await promptCacheHeaders(ctx, config, route)
371
394
  return await requestNativeCompaction({
372
395
  baseURL: config.baseURL,
373
396
  model: options.model,
374
397
  input,
375
398
  instructions: options.system,
376
- promptCacheKey: promptCacheKey(route),
399
+ promptCacheKey: promptCacheKey(route, config),
400
+ promptCacheRetention: promptCacheRetention(config),
377
401
  idempotencyKey: randomUUID(),
378
402
  tools: options.tools,
379
403
  headers,
@@ -731,7 +755,7 @@ function checkpointReplayRecord(messages, store) {
731
755
  return { marker, record }
732
756
  }
733
757
 
734
- function nativeReplayBody(options, route, nativeOutput, tailInput) {
758
+ function nativeReplayBody(options, route, config, nativeOutput, tailInput) {
735
759
  return {
736
760
  model: options.model,
737
761
  input: [...structuredClone(nativeOutput), ...structuredClone(tailInput)],
@@ -739,7 +763,8 @@ function nativeReplayBody(options, route, nativeOutput, tailInput) {
739
763
  store: false,
740
764
  ...(options.tools !== undefined ? { tools: responsesTools(options.tools) } : {}),
741
765
  ...(options.system !== undefined ? { instructions: options.system } : {}),
742
- ...(promptCacheKey(route) ? { prompt_cache_key: promptCacheKey(route) } : {}),
766
+ ...(promptCacheKey(route, config) ? { prompt_cache_key: promptCacheKey(route, config) } : {}),
767
+ ...(promptCacheRetention(config) ? { prompt_cache_retention: promptCacheRetention(config) } : {}),
743
768
  }
744
769
  }
745
770
 
@@ -751,7 +776,7 @@ async function* nativeCheckpointReplayStream(options, config, portableStore, ctx
751
776
  ? await resolveModelImageSupport(llm, route, options.signal)
752
777
  : 'supported'
753
778
  const imageOptions = { resolveImage: attachmentImageResolver(ctx), imageSupport, signal: options.signal, maxRequestImageBytes: config.maxRequestImageBytes }
754
- const nativeOutput = await hydrateNativeImageReferences(record.nativeOutput, imageOptions)
779
+ const nativeOutput = await hydrateNativeImageReferences(checkpointNativeReplacementHistory(record), imageOptions)
755
780
  const tailInput = await buildPortableResponsesInputWithImages(
756
781
  (options.messages ?? []).slice(marker.index + 1),
757
782
  portableStore,
@@ -762,8 +787,8 @@ async function* nativeCheckpointReplayStream(options, config, portableStore, ctx
762
787
  try {
763
788
  const response = await fetchSse(
764
789
  `${config.baseURL}/responses`,
765
- nativeReplayBody(options, route, nativeOutput, tailInput),
766
- mergeFeatureHeader(await authenticatedHeaders(ctx, config, options.sessionId)),
790
+ nativeReplayBody(options, route, config, nativeOutput, tailInput),
791
+ mergeFeatureHeader(await promptCacheHeaders(ctx, config, route)),
767
792
  replaySignals.signal,
768
793
  config.timeoutMs + 1000,
769
794
  { maxResponseBytes: config.maxResponseBytes },
@@ -822,7 +847,7 @@ async function prepareRemoteCompaction(options, config, portableStore, ctx, sess
822
847
  const route = currentRoute(options, config)
823
848
  const lease = sessionTracker?.capture(route.sessionId)
824
849
  lease?.assert('request-start')
825
- const headers = await authenticatedHeaders(ctx, config, options.sessionId)
850
+ const headers = await promptCacheHeaders(ctx, config, route)
826
851
  responsesTools(options.tools)
827
852
  const llm = ctx?.llm ?? ctx?.get?.('llm')
828
853
  const imageSupport = typeof llm?.resolveModelInfo === 'function'
@@ -864,7 +889,8 @@ function portableMarkerTextWithSummary(id, model, usage, summary) {
864
889
  async function commitRemoteCompaction(prepared, result, portableStore, config, summary, usage) {
865
890
  const { history, route, lease, input, imageReferences } = prepared
866
891
  lease?.assert('commit')
867
- const persistedNativeOutput = persistNativeImageReferences(result.output, imageReferences)
892
+ const replacementHistory = buildNativeReplacementHistory(input, result.compaction)
893
+ const persistedNativeOutput = persistNativeImageReferences(replacementHistory, imageReferences)
868
894
  const persistedPortableInput = persistNativeImageReferences(input, imageReferences)
869
895
  const id = randomUUID()
870
896
  const parent = latestPortableMarker(history)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-lcx-codex",
3
- "version": "0.3.1",
3
+ "version": "0.3.3",
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",