dsh-llm-verifier 0.3.1 → 0.4.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.md +133 -9
- package/lib/auto-B5V49e-A.js +1517 -0
- package/lib/auto-B5V49e-A.js.map +1 -0
- package/lib/{caller-DJd_FlrQ.js → caller-DR_C7ueP.js} +154 -20
- package/lib/caller-DR_C7ueP.js.map +1 -0
- package/lib/caller.js +2 -2
- package/lib/client.js +804 -29
- package/lib/client.js.map +1 -1
- package/lib/core.js +226 -3
- package/lib/core.js.map +1 -1
- package/lib/index.js +1014 -1349
- package/lib/index.js.map +1 -1
- package/lib/replay.js +157 -0
- package/lib/replay.js.map +1 -0
- package/lib/types/auto.js +1 -1
- package/lib/types/auto.js.map +1 -1
- package/lib/types/caller.d.ts +65 -0
- package/lib/types/caller.d.ts.map +1 -1
- package/lib/types/caller.js +113 -5
- package/lib/types/caller.js.map +1 -1
- package/lib/types/client-i18n.d.ts +163 -6
- package/lib/types/client-i18n.d.ts.map +1 -1
- package/lib/types/client-i18n.js +137 -26
- package/lib/types/client-i18n.js.map +1 -1
- package/lib/types/client.d.ts +30 -0
- package/lib/types/client.d.ts.map +1 -1
- package/lib/types/client.js +94 -9
- package/lib/types/client.js.map +1 -1
- package/lib/types/config.d.ts +33 -0
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/config.js +17 -2
- package/lib/types/config.js.map +1 -1
- package/lib/types/core.d.ts +84 -0
- package/lib/types/core.d.ts.map +1 -1
- package/lib/types/core.js +222 -2
- package/lib/types/core.js.map +1 -1
- package/lib/types/criteria.d.ts +33 -0
- package/lib/types/criteria.d.ts.map +1 -0
- package/lib/types/criteria.js +67 -0
- package/lib/types/criteria.js.map +1 -0
- package/lib/types/decisions.d.ts +84 -0
- package/lib/types/decisions.d.ts.map +1 -0
- package/lib/types/decisions.js +209 -0
- package/lib/types/decisions.js.map +1 -0
- package/lib/types/engine.d.ts +54 -1
- package/lib/types/engine.d.ts.map +1 -1
- package/lib/types/engine.js +175 -12
- package/lib/types/engine.js.map +1 -1
- package/lib/types/index.d.ts +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +392 -38
- package/lib/types/index.js.map +1 -1
- package/lib/types/replay.d.ts +88 -0
- package/lib/types/replay.d.ts.map +1 -0
- package/lib/types/replay.js +136 -0
- package/lib/types/replay.js.map +1 -0
- package/lib/types/router.d.ts +29 -5
- package/lib/types/router.d.ts.map +1 -1
- package/lib/types/router.js +271 -45
- package/lib/types/router.js.map +1 -1
- package/lib/types/statistics.d.ts +10 -1
- package/lib/types/statistics.d.ts.map +1 -1
- package/lib/types/statistics.js +35 -7
- package/lib/types/statistics.js.map +1 -1
- package/lib/types/top-logprobs.d.ts +36 -0
- package/lib/types/top-logprobs.d.ts.map +1 -1
- package/lib/types/top-logprobs.js +41 -14
- package/lib/types/top-logprobs.js.map +1 -1
- package/package.json +6 -1
- package/scripts/eval-replay.mjs +118 -0
- package/src/auto.ts +1 -1
- package/src/caller.test.ts +62 -1
- package/src/caller.ts +124 -4
- package/src/client-i18n.ts +137 -25
- package/src/client.test.ts +21 -0
- package/src/client.tsx +145 -7
- package/src/config.test.ts +32 -0
- package/src/config.ts +49 -2
- package/src/core.test.ts +95 -0
- package/src/core.ts +217 -2
- package/src/criteria.test.ts +60 -0
- package/src/criteria.ts +76 -0
- package/src/decisions.test.ts +150 -0
- package/src/decisions.ts +244 -0
- package/src/engine.test.ts +131 -0
- package/src/engine.ts +167 -10
- package/src/index.test.ts +278 -8
- package/src/index.ts +373 -37
- package/src/replay.test.ts +82 -0
- package/src/replay.ts +155 -0
- package/src/router.test.ts +217 -5
- package/src/router.ts +286 -47
- package/src/statistics.test.ts +49 -1
- package/src/statistics.ts +44 -7
- package/src/top-logprobs.test.ts +28 -0
- package/src/top-logprobs.ts +56 -8
- package/lib/caller-DJd_FlrQ.js.map +0 -1
package/src/statistics.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises'
|
|
|
3
3
|
import { dirname, join } from 'node:path'
|
|
4
4
|
import type { RunStats } from './engine.ts'
|
|
5
5
|
|
|
6
|
-
export const VERIFIER_TOOL_NAMES = ['verifier_route_classify', 'verifier_compare', 'verifier_select', 'verifier_track', 'verifier_current_session'] as const
|
|
6
|
+
export const VERIFIER_TOOL_NAMES = ['verifier_route_classify', 'verifier_compare', 'verifier_select', 'verifier_track', 'verifier_best_of_n', 'verifier_current_session'] as const
|
|
7
7
|
export type VerifierToolName = typeof VERIFIER_TOOL_NAMES[number]
|
|
8
8
|
|
|
9
9
|
export interface VerdictSummary {
|
|
@@ -53,6 +53,7 @@ export function summarizeVerdict(toolName: VerifierToolName, value: unknown, pha
|
|
|
53
53
|
const winner = row.winner === 'A' || row.winner === 'B' || row.winner === 'tie' ? row.winner : undefined
|
|
54
54
|
if (toolName === 'verifier_route_classify') return { phase, outcome: 'classified' }
|
|
55
55
|
if (toolName === 'verifier_select') {
|
|
56
|
+
if (row.identical === true) return { phase, outcome: 'identical-candidates' }
|
|
56
57
|
const index = numberAt('index')
|
|
57
58
|
const best = index === undefined ? undefined : scores[index]
|
|
58
59
|
return { phase, outcome: 'ranked', ...(best !== undefined ? { score: best } : {}) }
|
|
@@ -80,23 +81,48 @@ export function summarizeVerdict(toolName: VerifierToolName, value: unknown, pha
|
|
|
80
81
|
const score = winner === 'B' ? scoreB : scoreA
|
|
81
82
|
return {
|
|
82
83
|
phase,
|
|
83
|
-
outcome: winner === 'tie' ? 'tie' : 'compared',
|
|
84
|
+
outcome: row.identical === true ? 'identical' : winner === 'tie' ? 'tie' : 'compared',
|
|
84
85
|
...(score !== undefined ? { score } : {}),
|
|
85
86
|
...(scoreB !== undefined ? { scoreB } : {}),
|
|
86
87
|
...(winner !== undefined ? { winner } : {}),
|
|
87
88
|
}
|
|
88
89
|
}
|
|
89
|
-
//
|
|
90
|
-
//
|
|
90
|
+
// The remaining tools are both measured against the fixed empty-work baseline. A best-of-N
|
|
91
|
+
// verdict is rendered with the GATE's shape, not the select tool's: the tournament shares it
|
|
92
|
+
// also returns are relative preferences (wins/counts) and mean nothing against
|
|
93
|
+
// `autoVerifyThreshold`, while its `score`/`baselineScore`/`winner` come from the very same
|
|
94
|
+
// empty-work comparison the final gate runs. The dashboard reads it exactly like an acceptance.
|
|
95
|
+
return acceptanceVerdict(row, phase, thresholds)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Verdict of a run that was measured against the fixed empty-work baseline.
|
|
100
|
+
*
|
|
101
|
+
* Shared by the automatic session acceptance and by `verifier_best_of_n`: both answer
|
|
102
|
+
* "is this good enough to conclude", and both are decided by the same three conditions.
|
|
103
|
+
* @param row - the rendered result.
|
|
104
|
+
* @param phase - which stage produced it.
|
|
105
|
+
* @param thresholds - resolved acceptance thresholds.
|
|
106
|
+
* @returns A gate-shaped verdict summary.
|
|
107
|
+
*/
|
|
108
|
+
function acceptanceVerdict(row: Record<string, unknown>, phase: string, thresholds: VerdictThresholds): VerdictSummary {
|
|
109
|
+
const numberAt = (key: string): number | undefined => (typeof row[key] === 'number' && Number.isFinite(row[key]) ? row[key] as number : undefined)
|
|
110
|
+
const winner = row.winner === 'A' || row.winner === 'B' || row.winner === 'tie' ? row.winner : undefined
|
|
111
|
+
// `score` is the run's own score and `baselineScore` the empty-work baseline it has to beat.
|
|
91
112
|
const score = numberAt('score') ?? numberAt('scoreA')
|
|
92
113
|
const baselineScore = numberAt('baselineScore')
|
|
93
114
|
const threshold = thresholds.autoVerifyThreshold
|
|
94
115
|
const criteria = Array.isArray(row.criteria)
|
|
95
116
|
? (row.criteria as unknown[])
|
|
96
117
|
.map(entry => (typeof entry === 'object' && entry !== null ? entry as Record<string, unknown> : {}))
|
|
97
|
-
|
|
118
|
+
// `score` is the shape a session acceptance emits (AcceptanceCriterion); `scoreA` is the
|
|
119
|
+
// shape a compare result uses. Reading only `scoreA` silently dropped EVERY per-criterion
|
|
120
|
+
// score a session acceptance ever produced: 11 of 11 stored records on the author's topic
|
|
121
|
+
// carry no criteria array at all, so the dashboard could never show which requirement
|
|
122
|
+
// failed. Keep both, because the compare-shaped value is still a valid input here.
|
|
123
|
+
.map(entry => ({ id: entry.id, score: typeof entry.score === 'number' ? entry.score : entry.scoreA }))
|
|
124
|
+
.filter((entry): entry is { id: string; score: number } => typeof entry.id === 'string' && typeof entry.score === 'number' && Number.isFinite(entry.score))
|
|
98
125
|
.slice(0, MAX_VERDICT_CRITERIA)
|
|
99
|
-
.map(entry => ({ id: entry.id as string, score: entry.scoreA as number }))
|
|
100
126
|
: []
|
|
101
127
|
// A session does not pass on the mean alone: one criterion below the threshold fails
|
|
102
128
|
// the record too, which is exactly what the live gate now enforces.
|
|
@@ -186,7 +212,16 @@ export interface StatisticsTotals {
|
|
|
186
212
|
tokens: number
|
|
187
213
|
cacheHits: number
|
|
188
214
|
cacheMisses: number
|
|
215
|
+
/** Share of score-cache lookups answered locally (no model call). */
|
|
189
216
|
cacheHitRate: number
|
|
217
|
+
/**
|
|
218
|
+
* Share of verifier input tokens served by the PROVIDER's prefix cache.
|
|
219
|
+
*
|
|
220
|
+
* A different thing from {@link cacheHitRate}: that one counts local score-cache lookups,
|
|
221
|
+
* this one counts tokens the backend billed as cache hits. It is the metric a warm-up or
|
|
222
|
+
* prompt-ordering change moves, and leaving the two merged hid a 30%-hit-rate prefix cache.
|
|
223
|
+
*/
|
|
224
|
+
prefixCacheHitRate: number
|
|
190
225
|
estimatedCostUsd: number
|
|
191
226
|
topLogprobScores: number
|
|
192
227
|
explicitTagScores: number
|
|
@@ -256,7 +291,7 @@ function tokens(stats: RunStats): number { return stats.inputTokens + stats.cach
|
|
|
256
291
|
function cleanError(value: string | undefined): string | undefined { return value === undefined ? undefined : value.slice(0, 500) }
|
|
257
292
|
|
|
258
293
|
function blankTotals(): StatisticsTotals {
|
|
259
|
-
return { invocations: 0, successes: 0, failures: 0, successRate: 0, averageDurationMs: 0, calls: 0, attempts: 0, retries: 0, inputTokens: 0, cachedInputTokens: 0, outputTokens: 0, reasoningTokens: 0, tokens: 0, cacheHits: 0, cacheMisses: 0, cacheHitRate: 0, estimatedCostUsd: 0, topLogprobScores: 0, explicitTagScores: 0 }
|
|
294
|
+
return { invocations: 0, successes: 0, failures: 0, successRate: 0, averageDurationMs: 0, calls: 0, attempts: 0, retries: 0, inputTokens: 0, cachedInputTokens: 0, outputTokens: 0, reasoningTokens: 0, tokens: 0, cacheHits: 0, cacheMisses: 0, cacheHitRate: 0, prefixCacheHitRate: 0, estimatedCostUsd: 0, topLogprobScores: 0, explicitTagScores: 0 }
|
|
260
295
|
}
|
|
261
296
|
|
|
262
297
|
function addRecord(target: StatisticsTotals, record: InvocationRecord): void {
|
|
@@ -283,6 +318,7 @@ function finishTotals(target: StatisticsTotals): StatisticsTotals {
|
|
|
283
318
|
target.averageDurationMs = target.invocations > 0 ? target.averageDurationMs / target.invocations : 0
|
|
284
319
|
target.successRate = ratio(target.successes, target.invocations)
|
|
285
320
|
target.cacheHitRate = ratio(target.cacheHits, target.cacheHits + target.cacheMisses)
|
|
321
|
+
target.prefixCacheHitRate = ratio(target.cachedInputTokens, target.inputTokens + target.cachedInputTokens)
|
|
286
322
|
return target
|
|
287
323
|
}
|
|
288
324
|
|
|
@@ -381,6 +417,7 @@ export function mergeStatisticsOverviews(overviews: readonly StatisticsOverview[
|
|
|
381
417
|
totals.averageDurationMs = ratio(weightedDuration, totals.invocations)
|
|
382
418
|
totals.successRate = ratio(totals.successes, totals.invocations)
|
|
383
419
|
totals.cacheHitRate = ratio(totals.cacheHits, totals.cacheHits + totals.cacheMisses)
|
|
420
|
+
totals.prefixCacheHitRate = ratio(totals.cachedInputTokens, totals.inputTokens + totals.cachedInputTokens)
|
|
384
421
|
const limit = Math.min(200, Math.max(1, Math.trunc(query.recentLimit ?? 40)))
|
|
385
422
|
return {
|
|
386
423
|
generatedAt: Date.now(), fromMs: query.fromMs, toMs: query.toMs,
|
package/src/top-logprobs.test.ts
CHANGED
|
@@ -42,6 +42,34 @@ describe('TopLogprobCapabilityCache persistence', () => {
|
|
|
42
42
|
} finally { rmSync(dir, { recursive: true, force: true }) }
|
|
43
43
|
})
|
|
44
44
|
|
|
45
|
+
it('forgets a mark and persists the removal, even when it is forgotten before hydration', async () => {
|
|
46
|
+
const dir = mkdtempSync(join(tmpdir(), 'dsh-verifier-caps-'))
|
|
47
|
+
try {
|
|
48
|
+
const file = join(dir, 'capabilities-v1.json')
|
|
49
|
+
writeFileSync(file, JSON.stringify({ version: 1, entries: { 'openai\0gpt-5': Date.now(), 'openai\0keep': Date.now() } }))
|
|
50
|
+
|
|
51
|
+
// Forgotten BEFORE the file is hydrated: hydration max-merges the file into memory, so a
|
|
52
|
+
// delete that only happened up front would be undone by the write this schedule performs.
|
|
53
|
+
const cache = new TopLogprobCapabilityCache(file)
|
|
54
|
+
cache.forget('openai', 'gpt-5')
|
|
55
|
+
await cache.flush()
|
|
56
|
+
expect(cache.isUnsupported('openai', 'gpt-5')).toBe(false)
|
|
57
|
+
// The other mark survives: forgetting one judge must not erase the topic's memory.
|
|
58
|
+
expect(cache.isUnsupported('openai', 'keep')).toBe(true)
|
|
59
|
+
|
|
60
|
+
// Persisted: a fresh instance (a restarted host) must not resurrect the stale answer.
|
|
61
|
+
const restarted = new TopLogprobCapabilityCache(file)
|
|
62
|
+
await restarted.ensureLoaded()
|
|
63
|
+
expect(restarted.isUnsupported('openai', 'gpt-5')).toBe(false)
|
|
64
|
+
expect(restarted.isUnsupported('openai', 'keep')).toBe(true)
|
|
65
|
+
|
|
66
|
+
// Forgetting an unmarked judge is a no-op that still settles.
|
|
67
|
+
restarted.forget('openai', 'never-marked')
|
|
68
|
+
await restarted.flush()
|
|
69
|
+
expect(restarted.isUnsupported('openai', 'never-marked')).toBe(false)
|
|
70
|
+
} finally { rmSync(dir, { recursive: true, force: true }) }
|
|
71
|
+
})
|
|
72
|
+
|
|
45
73
|
it('re-probes a mark that expires while the process is running', () => {
|
|
46
74
|
let now = 1_000_000
|
|
47
75
|
const cache = new TopLogprobCapabilityCache(undefined, () => now)
|
package/src/top-logprobs.ts
CHANGED
|
@@ -5,6 +5,25 @@ import { dirname, isAbsolute, join, resolve } from 'node:path'
|
|
|
5
5
|
import type { CompletionLogprobs, TokenAlternative } from './core.ts'
|
|
6
6
|
import type { UsageStats, VerifierImage } from './caller.ts'
|
|
7
7
|
|
|
8
|
+
/**
|
|
9
|
+
* The two scoring channels are the logprob expectation (this file) and the explicit tag reply
|
|
10
|
+
* (caller.ts). Upstream has a THIRD one worth knowing about before inventing anything new:
|
|
11
|
+
* when an open-model server does not emit the score tags at all, it prefills the tag itself and
|
|
12
|
+
* constrains the next token to the twenty scale letters, then reads that token's distribution
|
|
13
|
+
* (llm-as-a-verifier `_score_tags_by_prefill`: vLLM/SGLang `continue_final_message` plus
|
|
14
|
+
* `structured_outputs`). That turns ANY OpenAI-compatible server into a distribution-scoring
|
|
15
|
+
* judge, which is strictly more informative than our explicit-tag channel's single sampled letter
|
|
16
|
+
* — it is why upstream can run K=1 and we average repeats instead.
|
|
17
|
+
*
|
|
18
|
+
* NOT implemented here, deliberately: the direct transport below speaks to whichever
|
|
19
|
+
* OpenAI-compatible endpoint a provider declares, and the prefill/grammar parameters are
|
|
20
|
+
* vLLM/SGLang extensions that a normal endpoint rejects. Two preconditions before adding it:
|
|
21
|
+
* (1) the DSH stream adapter exposes prefill or a constrained-decoding option, or the route is
|
|
22
|
+
* known to be a local inference server; (2) the capability probe can detect support at runtime and
|
|
23
|
+
* degrade to explicit tags — NEVER keyed off a provider or model name (AGENTS.md rule 7). If it
|
|
24
|
+
* lands, it belongs in `callTopLogprobs` as an opt-in third mode, and `autoTrackRepeats` could
|
|
25
|
+
* then drop.
|
|
26
|
+
*/
|
|
8
27
|
export interface TopLogprobRoute {
|
|
9
28
|
baseURL: string
|
|
10
29
|
apiKey?: string
|
|
@@ -151,20 +170,49 @@ export class TopLogprobCapabilityCache {
|
|
|
151
170
|
|
|
152
171
|
markUnsupported(provider: string, model: string): void {
|
|
153
172
|
this.unsupported.set(provider + '\0' + model, this.now())
|
|
173
|
+
this.persist()
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Forget one provider/model mark so the next call re-probes instead of replaying a cached answer.
|
|
178
|
+
*
|
|
179
|
+
* The judge probe exists to answer "which scoring channel is this judge on". Replaying a mark
|
|
180
|
+
* written up to {@link CAPABILITY_TTL_MS} ago — possibly under a different provider
|
|
181
|
+
* configuration — would answer a different, stale question. The removal is persisted, so a host
|
|
182
|
+
* restart cannot resurrect the old mark.
|
|
183
|
+
*
|
|
184
|
+
* The delete is repeated INSIDE the serialized write: hydration max-merges the file into memory,
|
|
185
|
+
* so deleting only beforehand would let the very write we schedule put the entry back.
|
|
186
|
+
* @param provider - provider id the mark belongs to.
|
|
187
|
+
* @param model - model id the mark belongs to.
|
|
188
|
+
*/
|
|
189
|
+
forget(provider: string, model: string): void {
|
|
190
|
+
const key = provider + '\0' + model
|
|
191
|
+
this.unsupported.delete(key)
|
|
192
|
+
if (this.file === undefined) return
|
|
193
|
+
this.writing = this.writing
|
|
194
|
+
.then(() => this.ensureLoaded())
|
|
195
|
+
.then(() => { this.unsupported.delete(key); return this.writeDocument() })
|
|
196
|
+
.catch(() => { /* capability memory is best-effort */ })
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/** Serialize behind hydration so an early mark never clobbers not-yet-loaded entries. */
|
|
200
|
+
private persist(): void {
|
|
154
201
|
if (this.file === undefined) return
|
|
155
|
-
// Serialize behind hydration so an early mark never clobbers not-yet-loaded entries.
|
|
156
202
|
this.writing = this.writing
|
|
157
203
|
.then(() => this.ensureLoaded())
|
|
158
|
-
.then(
|
|
159
|
-
const snapshot: CapabilityDocument = { version: 1, entries: Object.fromEntries(this.unsupported) }
|
|
160
|
-
await mkdir(dirname(this.file!), { recursive: true })
|
|
161
|
-
const temporary = this.file! + '.tmp-' + process.pid
|
|
162
|
-
await writeFile(temporary, JSON.stringify(snapshot), 'utf8')
|
|
163
|
-
try { await rename(temporary, this.file!) } catch (error) { await unlink(temporary).catch(() => {}); throw error }
|
|
164
|
-
})
|
|
204
|
+
.then(() => this.writeDocument())
|
|
165
205
|
.catch(() => { /* capability memory is best-effort; the next mark rewrites the file */ })
|
|
166
206
|
}
|
|
167
207
|
|
|
208
|
+
private async writeDocument(): Promise<void> {
|
|
209
|
+
const snapshot: CapabilityDocument = { version: 1, entries: Object.fromEntries(this.unsupported) }
|
|
210
|
+
await mkdir(dirname(this.file!), { recursive: true })
|
|
211
|
+
const temporary = this.file! + '.tmp-' + process.pid
|
|
212
|
+
await writeFile(temporary, JSON.stringify(snapshot), 'utf8')
|
|
213
|
+
try { await rename(temporary, this.file!) } catch (error) { await unlink(temporary).catch(() => {}); throw error }
|
|
214
|
+
}
|
|
215
|
+
|
|
168
216
|
/** Resolves once the trailing persistence attempt settles; exposed for tests. */
|
|
169
217
|
flush(): Promise<void> { return this.writing }
|
|
170
218
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"caller-DJd_FlrQ.js","names":[],"sources":["../src/top-logprobs.ts","../src/caller.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis'\nimport { credentialRef } from '@deepseek-ai/dsh-credentials'\nimport { mkdir, readFile, rename, unlink, writeFile } from 'node:fs/promises'\nimport { dirname, isAbsolute, join, resolve } from 'node:path'\nimport type { CompletionLogprobs, TokenAlternative } from './core.ts'\nimport type { UsageStats, VerifierImage } from './caller.ts'\n\nexport interface TopLogprobRoute {\n baseURL: string\n apiKey?: string\n headers?: Record<string, string>\n deepSeekThinking: boolean\n}\nexport interface TopLogprobCompletion extends CompletionLogprobs { usage: UsageStats; scoringMode: 'top-logprobs' }\nexport class TopLogprobsUnsupportedError extends Error { constructor(message: string) { super(message); this.name = 'TopLogprobsUnsupportedError' } }\n/**\n * A provider-level rejection of the direct transport that is not a logprobs\n * capability answer (bad request, auth, quota, malformed body). It downgrades\n * this topic to the DSH stream instead of failing the whole verification.\n */\nexport class TopLogprobsRouteError extends TopLogprobsUnsupportedError { constructor(message: string, readonly status?: number) { super(message); this.name = 'TopLogprobsRouteError' } }\n\nfunction object(value: unknown): Record<string, unknown> | undefined { return typeof value === 'object' && value !== null && !Array.isArray(value) ? value as Record<string, unknown> : undefined }\nfunction text(value: unknown): string | undefined { return typeof value === 'string' && value.trim() ? value.trim() : undefined }\nfunction endpoint(baseURL: string): string { return baseURL.replace(/\\/+$/, '') + '/chat/completions' }\nfunction dataUrl(image: VerifierImage): string { return 'data:' + image.mediaType + ';base64,' + Buffer.from(image.data.buffer, image.data.byteOffset, image.data.byteLength).toString('base64') }\n\nasync function credential(ctx: Context, name: string | undefined): Promise<string | undefined> {\n if (!name) return undefined\n const provider = ctx.get('credentials')\n return (await provider?.resolve(credentialRef(name)))?.value\n}\n\nexport async function resolveTopLogprobRoute(ctx: Context, provider: string): Promise<TopLogprobRoute | undefined> {\n const settings = ctx.get('settings')\n if (provider === 'deepseek-official') {\n const value = settings ? object(settings.get('llm-deepseek' as never)) ?? {} : {}\n const apiKeyEnv = text(value.apiKeyEnv) ?? 'DEEPSEEK_API_KEY'\n const apiKey = await credential(ctx, apiKeyEnv)\n if (!apiKey) return undefined\n return { baseURL: text(value.baseURL) ?? 'https://api.deepseek.com', apiKey, deepSeekThinking: true }\n }\n if (!settings) return undefined\n const root = object(settings.get('llm-pi-ai' as never))\n const profiles = object(root?.providers)\n const profile = object(profiles?.[provider])\n // Only explicitly OpenAI-compatible profiles are safe to serialize directly.\n // Other DSH adapters keep their private protocol and use the explicit-tag fallback.\n if (!profile || profile.api !== 'openai-completions') return undefined\n const baseURL = text(profile.baseURL)\n if (!baseURL || !/^https:\\/\\//i.test(baseURL)) return undefined\n const apiKey = await credential(ctx, text(profile.apiKeyEnv))\n const rawHeaders = object(profile.headers)\n const headers = rawHeaders === undefined ? undefined : Object.fromEntries(Object.entries(rawHeaders).filter((entry): entry is [string, string] => typeof entry[1] === 'string'))\n return { baseURL, ...(apiKey ? { apiKey } : {}), ...(headers ? { headers } : {}), deepSeekThinking: false }\n}\n\nexport async function callTopLogprobs(route: TopLogprobRoute, model: string, prompt: string, maxTokens: number, reasoningEffort: string | undefined, signal?: AbortSignal, images?: readonly VerifierImage[], attempt = 1, temperature = 0.2): Promise<TopLogprobCompletion> {\n const content: string | Record<string, unknown>[] = images?.length ? [{ type: 'text', text: prompt }, ...images.map(image => ({ type: 'image_url', image_url: { url: dataUrl(image) } }))] : prompt\n const thinking = route.deepSeekThinking && reasoningEffort ? reasoningEffort === 'off' ? { thinking: { type: 'disabled' } } : { thinking: { type: 'enabled' }, reasoning_effort: reasoningEffort } : {}\n const response = await fetch(endpoint(route.baseURL), {\n method: 'POST', redirect: 'error', signal,\n headers: { 'content-type': 'application/json', ...(route.apiKey ? { authorization: 'Bearer ' + route.apiKey } : {}), ...route.headers },\n body: JSON.stringify({ model, messages: [{ role: 'user', content }], max_tokens: maxTokens, temperature, logprobs: true, top_logprobs: 20, ...thinking }),\n })\n const raw = await response.text()\n if (!response.ok) {\n const excerpt = raw.slice(0, 1000)\n const message = 'llm-verifier: top_logprobs request failed with HTTP ' + response.status + ': ' + excerpt\n if ([400, 404, 405, 415, 422].includes(response.status) && /logprob|top_logprobs|unsupported|unknown (?:field|parameter)|unrecognized (?:field|parameter)|not support/i.test(excerpt)) throw new TopLogprobsUnsupportedError('provider rejected top_logprobs: HTTP ' + response.status + ' ' + excerpt)\n // Throttling and server faults stay generic so the shared retry wrapper can\n // attempt again; every other rejection downgrades to the DSH stream.\n if (response.status === 408 || response.status === 409 || response.status === 429 || response.status >= 500) throw new Error(message)\n throw new TopLogprobsRouteError(message, response.status)\n }\n let body: Record<string, unknown>\n try { body = object(JSON.parse(raw)) ?? {} } catch { throw new TopLogprobsRouteError('llm-verifier: top_logprobs endpoint returned invalid JSON', response.status) }\n const choices = Array.isArray(body.choices) ? body.choices : []\n const choice = object(choices[0])\n const message = object(choice?.message)\n const answer = typeof message?.content === 'string' ? message.content : ''\n const logprobs = object(choice?.logprobs)\n const rows = Array.isArray(logprobs?.content) ? logprobs.content : []\n if (!rows.length) throw new TopLogprobsUnsupportedError('provider returned no token logprobs')\n const tokens: string[] = []\n const positions: TokenAlternative[][] = []\n for (const rawRow of rows) {\n const row = object(rawRow) ?? {}\n const token = typeof row.token === 'string' ? row.token : ''\n tokens.push(token)\n const top = Array.isArray(row.top_logprobs) ? row.top_logprobs : []\n const alternatives = top.flatMap(value => { const item = object(value); return item && typeof item.token === 'string' && typeof item.logprob === 'number' ? [{ token: item.token, logprob: item.logprob }] : [] })\n if (!alternatives.length && typeof row.logprob === 'number') alternatives.push({ token, logprob: row.logprob })\n positions.push(alternatives)\n }\n const rawUsage = object(body.usage) ?? {}\n const promptDetails = object(rawUsage.prompt_tokens_details) ?? {}\n const completionDetails = object(rawUsage.completion_tokens_details) ?? {}\n const cached = Number(rawUsage.prompt_cache_hit_tokens ?? promptDetails.cached_tokens ?? 0) || 0\n const input = Number(rawUsage.prompt_tokens ?? 0) || 0\n return { text: answer, tokens, positions, scoringMode: 'top-logprobs', usage: { calls: 1, attempts: attempt, retries: attempt - 1, inputTokens: Math.max(0, input - cached), cachedInputTokens: cached, outputTokens: Number(rawUsage.completion_tokens ?? 0) || 0, reasoningTokens: Number(completionDetails.reasoning_tokens ?? 0) || 0 } }\n}\n\n/** Marks older than this are dropped on hydration so a provider that later gains logprobs support is re-probed. */\nexport const CAPABILITY_TTL_MS = 24 * 60 * 60 * 1000\n\ninterface CapabilityDocument { version: 1; entries: Record<string, number> }\n\n/** Resolves the capability memory file beside the score cache inside the topic verifier directory. */\nexport function resolveCapabilityFile(cacheDir: string, cwd = process.cwd()): string {\n const root = isAbsolute(cacheDir) ? cacheDir : resolve(cwd, cacheDir)\n return join(root, 'capabilities-v1.json')\n}\n\nexport class TopLogprobCapabilityCache {\n private readonly unsupported = new Map<string, number>()\n private loaded = false\n private hydrating: Promise<void> | undefined\n private writing: Promise<void> = Promise.resolve()\n\n constructor(private readonly file?: string, private readonly now: () => number = Date.now) {}\n\n /** Expired marks are dropped so a provider that later gains logprobs support is re-probed. */\n isUnsupported(provider: string, model: string): boolean {\n const key = provider + '\\0' + model\n const markedAt = this.unsupported.get(key)\n if (markedAt === undefined) return false\n if (this.now() - markedAt > CAPABILITY_TTL_MS) { this.unsupported.delete(key); return false }\n return true\n }\n\n /** Hydrates persisted marks once; in-process marks always win over file contents. */\n async ensureLoaded(): Promise<void> {\n if (this.loaded || this.file === undefined) return\n this.hydrating ??= (async () => {\n try {\n const document = JSON.parse(await readFile(this.file!, 'utf8')) as CapabilityDocument\n const entries = document !== null && typeof document === 'object' && document.version === 1 && typeof document.entries === 'object' && document.entries !== null ? document.entries : {}\n const now = this.now()\n for (const [key, markedAt] of Object.entries(entries)) {\n if (typeof markedAt !== 'number' || !Number.isFinite(markedAt) || markedAt < 0 || now - markedAt > CAPABILITY_TTL_MS) continue\n // Max-merge: never let an older persisted stamp clobber a fresher in-process probe.\n const existing = this.unsupported.get(key)\n if (existing === undefined || existing < markedAt) this.unsupported.set(key, markedAt)\n }\n } catch { /* a missing or unreadable file simply starts empty */ }\n this.loaded = true\n })()\n await this.hydrating\n }\n\n markUnsupported(provider: string, model: string): void {\n this.unsupported.set(provider + '\\0' + model, this.now())\n if (this.file === undefined) return\n // Serialize behind hydration so an early mark never clobbers not-yet-loaded entries.\n this.writing = this.writing\n .then(() => this.ensureLoaded())\n .then(async () => {\n const snapshot: CapabilityDocument = { version: 1, entries: Object.fromEntries(this.unsupported) }\n await mkdir(dirname(this.file!), { recursive: true })\n const temporary = this.file! + '.tmp-' + process.pid\n await writeFile(temporary, JSON.stringify(snapshot), 'utf8')\n try { await rename(temporary, this.file!) } catch (error) { await unlink(temporary).catch(() => {}); throw error }\n })\n .catch(() => { /* capability memory is best-effort; the next mark rewrites the file */ })\n }\n\n /** Resolves once the trailing persistence attempt settles; exposed for tests. */\n flush(): Promise<void> { return this.writing }\n}\n","import { BlockAssembler, ReasoningEffortId, createUserMessage, type ContentBlock, type FinishReason, type LlmRuntime } from '@deepseek-ai/dsh-llm'\nimport * as LlmModule from '@deepseek-ai/dsh-llm'\n\nfunction deepFreeze<T>(value: T): T {\n const mod = LlmModule as unknown as Record<string, unknown>\n if (typeof mod.deepFreeze === 'function') {\n return (mod.deepFreeze as Function)(value)\n }\n if (value && typeof value === 'object' && !Object.isFrozen(value)) {\n Object.freeze(value)\n for (const key of Object.keys(value)) {\n deepFreeze((value as Record<string, unknown>)[key])\n }\n }\n return value\n}\nimport type { AttachmentStore } from '@deepseek-ai/dsh-attachment'\nimport type { CompletionLogprobs } from './core.ts'\nimport { TopLogprobCapabilityCache, TopLogprobsUnsupportedError, callTopLogprobs, resolveTopLogprobRoute } from './top-logprobs.ts'\nimport type { Context } from '@deepseek-ai/cordis'\n\nexport interface VerifierClientConfig {\n ctx: Context\n llm: LlmRuntime\n attachments: AttachmentStore\n topLogprobCapabilities: TopLogprobCapabilityCache\n provider: string\n model: string\n /** User-facing judge name for tool output; cosmetic only, never part of the scoring cache identity. */\n label?: string\n reasoningEffort?: string\n maxTokens: number\n temperature: number\n timeoutMs: number\n maxRetries: number\n retryBaseDelayMs: number\n limiter?: RequestLimiter\n}\n\nexport interface VerifierImage {\n data: Uint8Array\n mediaType: 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif'\n}\n\nexport interface UsageStats {\n calls: number\n attempts: number\n retries: number\n inputTokens: number\n cachedInputTokens: number\n outputTokens: number\n reasoningTokens: number\n}\n\nexport type ScoringMode = 'top-logprobs' | 'explicit-tag'\nexport interface VerifierCompletion extends CompletionLogprobs { usage: UsageStats; scoringMode: ScoringMode }\n\nfunction failureMessage(finish: FinishReason): string | undefined {\n if (finish.kind === 'error' || finish.kind === 'aborted') return finish.failure.message\n if (finish.kind === 'max-tokens') return 'verifier response reached max tokens before completing its answer'\n return undefined\n}\n\nasync function delay(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) throw signal.reason\n await new Promise<void>((resolve, reject) => {\n const timer = setTimeout(resolve, ms)\n const abort = () => { clearTimeout(timer); reject(signal?.reason) }\n signal?.addEventListener('abort', abort, { once: true })\n })\n}\n\nfunction usage(attempts: number, value = {} as { inputTokens?: number; outputTokens?: number; cacheReadTokens?: number; cacheWriteTokens?: number; reasoningTokens?: number }): UsageStats {\n return { calls: 1, attempts, retries: attempts - 1, inputTokens: value.inputTokens ?? 0, cachedInputTokens: (value.cacheReadTokens ?? 0) + (value.cacheWriteTokens ?? 0), outputTokens: value.outputTokens ?? 0, reasoningTokens: value.reasoningTokens ?? 0 }\n}\n\n/** Transient failures worth another attempt; anything else fails fast. */\nconst RETRYABLE_MESSAGE = /rate|quota|timeout|timed out|temporar|network|fetch|socket|5\\d\\d/i\n\n/**\n * Run one logical verifier request under the configured timeout, retrying\n * transient failures with exponential backoff.\n *\n * Every channel goes through this wrapper — including the direct top_logprobs\n * transport, which used to bypass both the timeout and the retry budget.\n * @param config - resolved verifier client configuration.\n * @param signal - caller's abort signal (tool call or turn boundary).\n * @param run - one attempt; receives its own deadline signal and 1-based attempt number.\n * @returns The first successful completion.\n */\nasync function retrying<T>(config: VerifierClientConfig, signal: AbortSignal | undefined, run: (signal: AbortSignal, attempt: number) => Promise<T>): Promise<T> {\n let attempt = 0\n while (true) {\n if (signal?.aborted) throw signal.reason\n attempt += 1\n const controller = new AbortController()\n let timedOut = false\n const timeout = setTimeout(() => { timedOut = true; controller.abort(new Error('llm-verifier: request timed out')) }, config.timeoutMs)\n const abort = () => controller.abort(signal?.reason)\n signal?.addEventListener('abort', abort, { once: true })\n try {\n return await run(controller.signal, attempt)\n } catch (error) {\n if (signal?.aborted) throw signal.reason\n // A deadline abort is retryable even when the adapter wraps the reason in\n // its own error type with an unrelated message.\n const retryable = timedOut || (error instanceof Error && RETRYABLE_MESSAGE.test(error.message))\n if (attempt > config.maxRetries || !retryable) throw error\n await delay(Math.min(30000, config.retryBaseDelayMs * 2 ** (attempt - 1) * (0.8 + Math.random() * 0.4)), signal)\n } finally {\n clearTimeout(timeout)\n signal?.removeEventListener('abort', abort)\n }\n }\n}\n\n/** One attachment per image object per process: retries must not duplicate attachments. */\nconst imageRefs = new WeakMap<VerifierImage, Promise<unknown>>()\n\nasync function callExplicitTag(config: VerifierClientConfig, prompt: string, signal: AbortSignal | undefined, images: readonly VerifierImage[] | undefined, attempt: number): Promise<VerifierCompletion> {\n const content: ContentBlock[] = [{ type: 'text', text: prompt }]\n for (const image of images ?? []) {\n let pending = imageRefs.get(image)\n if (pending === undefined) {\n const promise = Promise.resolve()\n .then(() => config.attachments.saveImage({ data: image.data, mediaType: image.mediaType }))\n .catch(error => {\n if (imageRefs.get(image) === pending) {\n imageRefs.delete(image)\n }\n throw error\n })\n pending = promise\n imageRefs.set(image, pending)\n }\n content.push({ type: 'image', attachment: await pending as never })\n }\n const messages = [createUserMessage({ content, source: { kind: 'plugin', plugin: 'dsh-llm-verifier' } })]\n const assembler = new BlockAssembler()\n const options = deepFreeze({\n provider: config.provider,\n model: config.model,\n ...(config.reasoningEffort ? { reasoningEffort: ReasoningEffortId(config.reasoningEffort) } : {}),\n messages,\n maxTokens: config.maxTokens,\n temperature: config.temperature,\n signal,\n })\n for await (const chunk of config.llm.stream(options)) assembler.push(chunk)\n const failed = failureMessage(assembler.finish)\n if (failed !== undefined) throw new Error('llm-verifier: model call failed: ' + failed)\n const text = assembler.blocks().filter((block): block is Extract<ContentBlock, { type: 'text' }> => block.type === 'text').map(block => block.text).join('')\n if (!text.trim()) throw new Error('llm-verifier: selected DSH model produced no text')\n // DSH adapters expose provider-neutral text/usage but not top-logprob candidates.\n // extractScore() therefore uses the model's explicit final A–T tags.\n return { text, tokens: [], positions: [], scoringMode: 'explicit-tag', usage: usage(attempt, assembler.usage) }\n}\n\nexport class RequestLimiter {\n private active = 0\n private readonly queue: Array<() => void> = []\n constructor(readonly limit: number) { if (!Number.isSafeInteger(limit) || limit < 1) throw new Error('llm-verifier: request concurrency limit must be a positive integer') }\n async run<T>(operation: () => Promise<T>, signal?: AbortSignal): Promise<T> {\n if (signal?.aborted) throw signal.reason\n if (this.active >= this.limit) await new Promise<void>((resolve, reject) => {\n const enter = () => { signal?.removeEventListener('abort', abort); resolve() }\n const abort = () => { const index = this.queue.indexOf(enter); if (index >= 0) this.queue.splice(index, 1); reject(signal?.reason) }\n this.queue.push(enter); signal?.addEventListener('abort', abort, { once: true })\n })\n if (signal?.aborted) {\n this.queue.shift()?.()\n throw signal.reason\n }\n this.active += 1\n try { return await operation() } finally { this.active -= 1; this.queue.shift()?.() }\n }\n}\n\n/** Best-effort pre-call channel prediction for cache identity only; callAutomatic() stays the runtime source of truth. */\nexport async function predictScoringChannel(config: VerifierClientConfig): Promise<ScoringMode> {\n await config.topLogprobCapabilities.ensureLoaded()\n return config.topLogprobCapabilities.isUnsupported(config.provider, config.model) ? 'explicit-tag' : 'top-logprobs'\n}\n\nasync function callAutomatic(config: VerifierClientConfig, prompt: string, signal: AbortSignal | undefined, images: readonly VerifierImage[] | undefined, attempt: number): Promise<VerifierCompletion> {\n await config.topLogprobCapabilities.ensureLoaded()\n if (!config.topLogprobCapabilities.isUnsupported(config.provider, config.model)) {\n const route = await resolveTopLogprobRoute(config.ctx, config.provider)\n if (route !== undefined) {\n try { return await callTopLogprobs(route, config.model, prompt, config.maxTokens, config.reasoningEffort, signal, images, attempt, config.temperature) }\n catch (error) {\n // Both a capability rejection and a non-retryable provider rejection of\n // the direct transport fall back to the DSH stream instead of failing\n // the whole verification.\n if (!(error instanceof TopLogprobsUnsupportedError)) throw error\n config.topLogprobCapabilities.markUnsupported(config.provider, config.model)\n }\n } else config.topLogprobCapabilities.markUnsupported(config.provider, config.model)\n }\n return callExplicitTag(config, prompt, signal, images, attempt)\n}\n\nexport async function callVerifier(config: VerifierClientConfig, prompt: string, signal?: AbortSignal, images?: readonly VerifierImage[]): Promise<VerifierCompletion> {\n const invoke = () => retrying(config, signal, (attemptSignal, attempt) => callAutomatic(config, prompt, attemptSignal, images, attempt))\n return config.limiter === undefined ? invoke() : config.limiter.run(invoke, signal)\n}\n\n/** Plain-text verifier call for conservative JSON routing; probability labels are intentionally bypassed. */\nexport async function callVerifierText(config: VerifierClientConfig, prompt: string, signal?: AbortSignal): Promise<VerifierCompletion> {\n const invoke = () => retrying(config, signal, (attemptSignal, attempt) => callExplicitTag(config, prompt, attemptSignal, undefined, attempt))\n return config.limiter === undefined ? invoke() : config.limiter.run(invoke, signal)\n}\nexport function addUsage(target: UsageStats, source: UsageStats): void { for (const key of ['calls', 'attempts', 'retries', 'inputTokens', 'cachedInputTokens', 'outputTokens', 'reasoningTokens'] as const) target[key] += source[key] }\nexport function emptyUsage(): UsageStats { return { calls: 0, attempts: 0, retries: 0, inputTokens: 0, cachedInputTokens: 0, outputTokens: 0, reasoningTokens: 0 } }\n"],"mappings":"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"}
|