dsh-reference-session-collector 0.0.0-stage → 0.1.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.
- package/README.de.md +75 -0
- package/README.en.md +110 -0
- package/README.es.md +74 -0
- package/README.fr.md +74 -0
- package/README.it.md +74 -0
- package/README.ja.md +68 -0
- package/README.ko.md +68 -0
- package/README.md +111 -3
- package/README.ru.md +73 -0
- package/assets/deepseek-v4/LICENSE.DeepSeek-V4-Pro.txt +21 -0
- package/assets/deepseek-v4/manifest.json +23 -0
- package/assets/deepseek-v4/tokenizer.json +267359 -0
- package/assets/deepseek-v4/tokenizer_config.json +34 -0
- package/cordis.patch.yml +11 -0
- package/dsh.plugin.json +22 -0
- package/lib/client.js +15 -0
- package/lib/index.d.ts +668 -0
- package/lib/index.js +2150 -0
- package/package.json +90 -4
- package/src/ambient.d.ts +9 -0
- package/src/client/index.ts +10 -0
- package/src/deepseek-v4-tokenizer.ts +212 -0
- package/src/index.ts +431 -0
- package/src/projection.ts +478 -0
- package/src/schema.ts +288 -0
- package/src/segment.ts +67 -0
- package/src/session-file-decode.ts +529 -0
- package/src/strip-injected.ts +46 -0
- package/src/surface.ts +392 -0
- package/src/sync.ts +434 -0
- package/src/token-count.ts +77 -0
package/package.json
CHANGED
|
@@ -1,6 +1,92 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-reference-session-collector",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"publishConfig": {
|
|
5
|
+
"registry": "https://registry.npmjs.org",
|
|
6
|
+
"tag": "latest",
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"description": "DSH Web 插件:会话原文投影同步器(DRS)——只读扫描 ~/.dsh/sessions 会话日志,解码后投影进自有 SQLite(segments/replaces/FTS5),经 /api/dsh-reference-session-collector 提供 surface 标记、召回对账与内容检索面。绝不写会话文件。",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"deepseek-harness",
|
|
12
|
+
"dsh",
|
|
13
|
+
"dsh-plugin",
|
|
14
|
+
"fts5",
|
|
15
|
+
"projection",
|
|
16
|
+
"search",
|
|
17
|
+
"session",
|
|
18
|
+
"sqlite",
|
|
19
|
+
"tokenizer"
|
|
20
|
+
],
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/drscrewdriver/dsh-reference-session-collector.git"
|
|
24
|
+
},
|
|
25
|
+
"type": "module",
|
|
26
|
+
"main": "lib/index.js",
|
|
27
|
+
"types": "lib/index.d.ts",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./lib/index.d.ts",
|
|
31
|
+
"default": "./lib/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./client": {
|
|
34
|
+
"default": "./lib/client.js"
|
|
35
|
+
},
|
|
36
|
+
"./cordis.patch.yml": "./cordis.patch.yml",
|
|
37
|
+
"./package.json": "./package.json"
|
|
38
|
+
},
|
|
39
|
+
"dsh": {
|
|
40
|
+
"bundle": {
|
|
41
|
+
"patch": "./cordis.patch.yml"
|
|
42
|
+
},
|
|
43
|
+
"client": {
|
|
44
|
+
"platform": "web"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "node -e \"require('fs').rmSync('lib',{recursive:true,force:true})\" && tsdown",
|
|
49
|
+
"prepack": "npm run build",
|
|
50
|
+
"typecheck": "tsc -p tsconfig.json --noEmit --pretty false",
|
|
51
|
+
"smoke": "node scripts/smoke-lib.mjs",
|
|
52
|
+
"test": "vitest run",
|
|
53
|
+
"lint": "eslint src tests eslint.config.js",
|
|
54
|
+
"check": "npm run typecheck && npm run lint && npm run test && npm run build && npm run smoke"
|
|
55
|
+
},
|
|
56
|
+
"files": [
|
|
57
|
+
"README.md",
|
|
58
|
+
"README.en.md",
|
|
59
|
+
"README.ja.md",
|
|
60
|
+
"README.ko.md",
|
|
61
|
+
"README.de.md",
|
|
62
|
+
"README.es.md",
|
|
63
|
+
"README.fr.md",
|
|
64
|
+
"README.ru.md",
|
|
65
|
+
"README.it.md",
|
|
66
|
+
"cordis.patch.yml",
|
|
67
|
+
"dsh.plugin.json",
|
|
68
|
+
"lib",
|
|
69
|
+
"src",
|
|
70
|
+
"assets"
|
|
71
|
+
],
|
|
72
|
+
"engines": {
|
|
73
|
+
"node": ">=22",
|
|
74
|
+
"dsh": "0.1.0-rc.2 || 0.1.0-rc.3 || 0.1.0-rc.6 || 0.1.0-rc.7 || 0.1.0-rc.8 || 0.1.1-rc.1 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.5-rc.3 || 0.1.7-rc.1 || 0.1.7-rc.2 || 0.2.0-rc.1 || 0.2.0-rc.2 || 0.2.1-rc.1 || 0.2.1-rc.2"
|
|
75
|
+
},
|
|
76
|
+
"license": "MIT",
|
|
77
|
+
"dependencies": {
|
|
78
|
+
"@huggingface/tokenizers": "0.1.3"
|
|
79
|
+
},
|
|
80
|
+
"devDependencies": {
|
|
81
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
82
|
+
"@eslint/js": "^10.0.1",
|
|
83
|
+
"@types/node": "^24.0.0",
|
|
84
|
+
"eslint": "^10.10.0",
|
|
85
|
+
"globals": "^17.12.0",
|
|
86
|
+
"tsdown": "^0.22.2",
|
|
87
|
+
"tsx": "^4.23.12",
|
|
88
|
+
"typescript": "^5.6.0",
|
|
89
|
+
"typescript-eslint": "^8.69.0",
|
|
90
|
+
"vitest": "^4.1.1"
|
|
91
|
+
}
|
|
92
|
+
}
|
package/src/ambient.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 环境侧声明:DRS 不 value-import 任何宿主官方包(session-file-decode 的
|
|
3
|
+
* `@deepseek-ai/dsh-session` 只是运行时可选软加载,失败即回退本地解码器),
|
|
4
|
+
* 这里给动态 import 一个最小模块面让 tsc 在零宿主依赖下可解析。
|
|
5
|
+
*/
|
|
6
|
+
declare module '@deepseek-ai/dsh-session' {
|
|
7
|
+
export function decodeStorageRecord(value: unknown): unknown[]
|
|
8
|
+
export function decodeSeqRanges(value: unknown, seq: number): number[]
|
|
9
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// DRS v0 client 半身:合法**空插件**(T1.4 占位,装机实锤修正)。
|
|
2
|
+
// ⚠ 不能是裸 `export {}`:client 半身同样经 cordis 插件加载器装载
|
|
3
|
+
// (dsh-plugin-dev 双半契约),形态必须为 function 或 {apply}——空对象
|
|
4
|
+
// 触发宿主 "invalid plugin, expect function or object with an
|
|
5
|
+
// 'apply' method, received object"。
|
|
6
|
+
// 设置卡/面板随消费方接线相(二期)在 apply 里长槽位注入;本版 apply 为
|
|
7
|
+
// 合法 no-op。tsdown 横幅负责 __ModuleLoader__.load 包装与 id==包名契约。
|
|
8
|
+
export const inject: string[] = []
|
|
9
|
+
|
|
10
|
+
export function apply(): void {}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ⚠ VENDORED(回搬件)——源自 dsh-context-compression-improved
|
|
3
|
+
* `packages/selector/src/deepseek-v4-tokenizer.ts`,回搬时点 2026-10-19。
|
|
4
|
+
* 回搬纪律:**文件级拷贝,禁止分叉**;CCI 侧修复须整文件重拷并复核资产哈希。
|
|
5
|
+
* 唯一授权 diff:导入路径 `./runtime/token-count.ts` → `./token-count.ts`
|
|
6
|
+
* (DRS 平铺布局,原目录树不存在),其余正文与源文件逐字节一致。
|
|
7
|
+
*/
|
|
8
|
+
/** Offline DeepSeek tokenizers backed by pinned official Hugging Face assets. */
|
|
9
|
+
|
|
10
|
+
import { createHash } from 'node:crypto'
|
|
11
|
+
import { readFileSync } from 'node:fs'
|
|
12
|
+
import { Tokenizer } from '@huggingface/tokenizers'
|
|
13
|
+
import type { ExactTokenizerTokenCount } from './token-count.ts'
|
|
14
|
+
|
|
15
|
+
const TOKENIZER_ID = 'deepseek-ai/DeepSeek-V4-Pro'
|
|
16
|
+
const TOKENIZER_REVISION = '0e1a0e5e52aea73055f50fef6f2423db370265b6'
|
|
17
|
+
const TOKENIZER_SHA256 = '8f9f37ca37fdc4f5fd36d5cf4d3b0e8392edb4e894fd10cc0d70b4957c8633cf'
|
|
18
|
+
const CONFIG_SHA256 = '6ac8c8dc065ed118161d02dd532749ae3f52c243deac27872134fae2f50d8547'
|
|
19
|
+
const VISION_TOKENIZER_ID = 'deepseek-ai/DeepSeek-V4-Flash-Vision-Exp'
|
|
20
|
+
const VISION_TOKENIZER_REVISION = '6821d6ad3681a4b137b066b76094fa82ebd0a380'
|
|
21
|
+
const VISION_TOKENIZER_SHA256 = 'c90dfa01249db1be4245780a052ede752e1361c612ac6d08e2bdada7d599476b'
|
|
22
|
+
const VISION_CONFIG_SHA256 = '6ac8c8dc065ed118161d02dd532749ae3f52c243deac27872134fae2f50d8547'
|
|
23
|
+
|
|
24
|
+
/** Auditable origin and compatibility mapping for one bundled tokenizer. */
|
|
25
|
+
export interface DeepSeekTokenizerArtifactOrigin {
|
|
26
|
+
/** Hugging Face repository the assets were pinned from. */
|
|
27
|
+
readonly repository: string
|
|
28
|
+
/** Immutable commit revision the assets were pinned from. */
|
|
29
|
+
readonly revision: string
|
|
30
|
+
/** Upstream license of the repository. */
|
|
31
|
+
readonly license: string
|
|
32
|
+
/** Exact API wire model ids served by this artifact. */
|
|
33
|
+
readonly modelIds: readonly string[]
|
|
34
|
+
readonly tokenizerSha256: string
|
|
35
|
+
readonly tokenizerConfigSha256: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Auditable origin and compatibility mapping for the bundled V4 Pro tokenizer. */
|
|
39
|
+
export const DEEPSEEK_V4_TOKENIZER_ARTIFACT: DeepSeekTokenizerArtifactOrigin = Object.freeze({
|
|
40
|
+
repository: TOKENIZER_ID,
|
|
41
|
+
revision: TOKENIZER_REVISION,
|
|
42
|
+
license: 'MIT',
|
|
43
|
+
tokenizerSha256: TOKENIZER_SHA256,
|
|
44
|
+
tokenizerConfigSha256: CONFIG_SHA256,
|
|
45
|
+
modelIds: Object.freeze(['deepseek-v4-flash', 'deepseek-v4-pro']),
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Auditable origin and compatibility mapping for the bundled V4 Flash Vision
|
|
50
|
+
* tokenizer. The vision repository ships a distinct `tokenizer.json` (it adds
|
|
51
|
+
* the `<|deepseek_image|>` special token), so the vision model must never be
|
|
52
|
+
* mapped onto the V4 Pro tokenizer as an alias.
|
|
53
|
+
*/
|
|
54
|
+
export const DEEPSEEK_VISION_TOKENIZER_ARTIFACT: DeepSeekTokenizerArtifactOrigin = Object.freeze({
|
|
55
|
+
repository: VISION_TOKENIZER_ID,
|
|
56
|
+
revision: VISION_TOKENIZER_REVISION,
|
|
57
|
+
license: 'MIT',
|
|
58
|
+
tokenizerSha256: VISION_TOKENIZER_SHA256,
|
|
59
|
+
tokenizerConfigSha256: VISION_CONFIG_SHA256,
|
|
60
|
+
modelIds: Object.freeze(['deepseek-v4-flash-vision-exp']),
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
/** Synchronous exact counter backed only by the verified local V4 artifacts. */
|
|
64
|
+
export interface DeepSeekV4TextTokenizer {
|
|
65
|
+
/** Count one fully determined text value with the official tokenizer. */
|
|
66
|
+
countText(text: string): ExactTokenizerTokenCount
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Integrity tuple for one tokenizer JSON asset. @internal */
|
|
70
|
+
export interface DeepSeekV4TokenizerAssetDescriptor {
|
|
71
|
+
readonly bytes: number
|
|
72
|
+
readonly sha256: string
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Injectable integrity manifest used by negative loader tests. @internal */
|
|
76
|
+
export interface DeepSeekV4TokenizerAssetIntegrity {
|
|
77
|
+
readonly tokenizer: DeepSeekV4TokenizerAssetDescriptor
|
|
78
|
+
readonly config: DeepSeekV4TokenizerAssetDescriptor
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
interface TokenizerArtifact {
|
|
82
|
+
readonly origin: DeepSeekTokenizerArtifactOrigin
|
|
83
|
+
readonly assetRoot: URL
|
|
84
|
+
readonly integrity: DeepSeekV4TokenizerAssetIntegrity
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Every bundled artifact is registered with independent asset roots, integrity
|
|
89
|
+
* manifests, and cache entries: one corrupted artifact must never disable the
|
|
90
|
+
* tokenizer serving the other model family.
|
|
91
|
+
*/
|
|
92
|
+
const ARTIFACTS: readonly TokenizerArtifact[] = Object.freeze([
|
|
93
|
+
Object.freeze({
|
|
94
|
+
origin: DEEPSEEK_V4_TOKENIZER_ARTIFACT,
|
|
95
|
+
assetRoot: new URL('../assets/deepseek-v4/', import.meta.url),
|
|
96
|
+
integrity: Object.freeze({
|
|
97
|
+
tokenizer: Object.freeze({ bytes: 6_367_146, sha256: TOKENIZER_SHA256 }),
|
|
98
|
+
config: Object.freeze({ bytes: 801, sha256: CONFIG_SHA256 }),
|
|
99
|
+
}),
|
|
100
|
+
}),
|
|
101
|
+
Object.freeze({
|
|
102
|
+
origin: DEEPSEEK_VISION_TOKENIZER_ARTIFACT,
|
|
103
|
+
assetRoot: new URL('../assets/deepseek-v4-vision-exp/', import.meta.url),
|
|
104
|
+
integrity: Object.freeze({
|
|
105
|
+
tokenizer: Object.freeze({ bytes: 6_367_257, sha256: VISION_TOKENIZER_SHA256 }),
|
|
106
|
+
config: Object.freeze({ bytes: 801, sha256: VISION_CONFIG_SHA256 }),
|
|
107
|
+
}),
|
|
108
|
+
}),
|
|
109
|
+
])
|
|
110
|
+
|
|
111
|
+
interface ArtifactCacheEntry {
|
|
112
|
+
readonly tokenizer?: DeepSeekV4TextTokenizer
|
|
113
|
+
readonly failure?: string
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const registryCache = new Map<DeepSeekTokenizerArtifactOrigin, ArtifactCacheEntry>()
|
|
117
|
+
|
|
118
|
+
function artifactForModel(modelId: string): TokenizerArtifact | undefined {
|
|
119
|
+
return ARTIFACTS.find(artifact => (artifact.origin.modelIds as readonly string[]).includes(modelId))
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Resolve the shared offline tokenizer for one compatible API model.
|
|
124
|
+
* Unknown models and a cached asset/runtime failure return `undefined`; callers
|
|
125
|
+
* must report unavailable instead of manufacturing a character estimate.
|
|
126
|
+
* @param modelId - exact DeepSeek API wire model id.
|
|
127
|
+
* @returns the shared verified tokenizer, or undefined when unsupported/unavailable.
|
|
128
|
+
*/
|
|
129
|
+
export function deepSeekV4TokenizerForModel(modelId: string): DeepSeekV4TextTokenizer | undefined {
|
|
130
|
+
const artifact = artifactForModel(modelId)
|
|
131
|
+
if (artifact === undefined) return undefined
|
|
132
|
+
const cached = registryCache.get(artifact.origin)
|
|
133
|
+
if (cached !== undefined) return cached.tokenizer
|
|
134
|
+
let entry: ArtifactCacheEntry
|
|
135
|
+
try {
|
|
136
|
+
const tokenizer = createDeepSeekV4TokenizerFromAssets(artifact.assetRoot, artifact.integrity, artifact.origin)
|
|
137
|
+
entry = { tokenizer }
|
|
138
|
+
} catch (error: unknown) {
|
|
139
|
+
entry = { failure: error instanceof Error ? error.message : String(error) }
|
|
140
|
+
}
|
|
141
|
+
registryCache.set(artifact.origin, entry)
|
|
142
|
+
return entry.tokenizer
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Read the cached initialization diagnostic for provider registration.
|
|
147
|
+
* @param modelId - optional exact model id; defaults to the V4 Pro artifact.
|
|
148
|
+
* @returns the first initialization failure for that artifact, or undefined.
|
|
149
|
+
*/
|
|
150
|
+
export function deepSeekV4TokenizerFailureReason(modelId?: string): string | undefined {
|
|
151
|
+
const artifact = modelId === undefined ? ARTIFACTS[0] : artifactForModel(modelId)
|
|
152
|
+
if (artifact === undefined) return undefined
|
|
153
|
+
return registryCache.get(artifact.origin)?.failure
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Complete pinned artifact inventory, in stable registration order. */
|
|
157
|
+
export function deepSeekTokenizerArtifacts(): readonly DeepSeekTokenizerArtifactOrigin[] {
|
|
158
|
+
return ARTIFACTS.map(artifact => artifact.origin)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Build a tokenizer from one local asset directory after byte/hash validation.
|
|
163
|
+
* This provider-private seam exists so tests can prove every failure branch
|
|
164
|
+
* without mutating the committed artifact.
|
|
165
|
+
* @param assetRoot - local URL containing tokenizer.json and tokenizer_config.json.
|
|
166
|
+
* @param integrity - expected byte length and SHA-256 for both files.
|
|
167
|
+
* @param origin - auditable identity recorded on every returned count.
|
|
168
|
+
* @returns a synchronous exact text counter.
|
|
169
|
+
* @internal
|
|
170
|
+
*/
|
|
171
|
+
export function createDeepSeekV4TokenizerFromAssets(
|
|
172
|
+
assetRoot: URL,
|
|
173
|
+
integrity: DeepSeekV4TokenizerAssetIntegrity,
|
|
174
|
+
origin: DeepSeekTokenizerArtifactOrigin = DEEPSEEK_V4_TOKENIZER_ARTIFACT,
|
|
175
|
+
): DeepSeekV4TextTokenizer {
|
|
176
|
+
const tokenizerJson = readVerifiedJson(assetRoot, 'tokenizer.json', integrity.tokenizer)
|
|
177
|
+
const tokenizerConfig = readVerifiedJson(assetRoot, 'tokenizer_config.json', integrity.config)
|
|
178
|
+
const runtime = new Tokenizer(tokenizerJson, tokenizerConfig)
|
|
179
|
+
return Object.freeze({
|
|
180
|
+
countText(text: string): ExactTokenizerTokenCount {
|
|
181
|
+
const tokens = runtime.encode(text, { add_special_tokens: false }).ids.length
|
|
182
|
+
return Object.freeze({
|
|
183
|
+
kind: 'exact-tokenizer',
|
|
184
|
+
tokens,
|
|
185
|
+
tokenizerId: origin.repository,
|
|
186
|
+
tokenizerRevision: origin.revision,
|
|
187
|
+
})
|
|
188
|
+
},
|
|
189
|
+
})
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function readVerifiedJson(
|
|
193
|
+
assetRoot: URL,
|
|
194
|
+
name: string,
|
|
195
|
+
descriptor: DeepSeekV4TokenizerAssetDescriptor,
|
|
196
|
+
): Record<string, unknown> {
|
|
197
|
+
const bytes = readFileSync(new URL(name, assetRoot))
|
|
198
|
+
if (bytes.byteLength !== descriptor.bytes) {
|
|
199
|
+
throw new Error(
|
|
200
|
+
`DeepSeek tokenizer asset ${name} has ${String(bytes.byteLength)} bytes; expected ${String(descriptor.bytes)}`,
|
|
201
|
+
)
|
|
202
|
+
}
|
|
203
|
+
const actualSha256 = createHash('sha256').update(bytes).digest('hex')
|
|
204
|
+
if (actualSha256 !== descriptor.sha256) {
|
|
205
|
+
throw new Error(`DeepSeek tokenizer asset ${name} failed SHA-256 verification`)
|
|
206
|
+
}
|
|
207
|
+
const parsed: unknown = JSON.parse(bytes.toString('utf8'))
|
|
208
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
|
|
209
|
+
throw new Error(`DeepSeek tokenizer asset ${name} must contain a JSON object`)
|
|
210
|
+
}
|
|
211
|
+
return parsed as Record<string, unknown>
|
|
212
|
+
}
|