mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
Four Context-page enhancements (lane-ctx-deep, F1-F4): - F1 context window breakdown: replace percentage-only card header with a stacked-bar breakdown of input / cached / output token buckets, plus a right-side gauge showing the live window occupancy ratio. - F2 compact Config tab: fold the sprawling profile Config editor into a Config tab on the Context page card, with the same yml-leaf ordering as the top-of-window profile picker. - F3 intervention marker: on the intervention timeline, emit a marker glyph at each user-intervention row (turn-flow-glyph-style) so the card scans as a single stream instead of a header + separate list. - F4 subagent drilldown: when a turn's tool trace hits a subagent, the Trace panel's Config + Output tabs get a second row of Subagent Config / Subagent Output tabs immediately below, driven by the same fold-in-place shape the parent panel already uses. 4 new renderer modules (compact-config-model / context-window-breakdown / intervention-timeline / subagent-drilldown), 6 new test files (41 tests, all node --test style), 4 QA shoot scripts for CDP-driven regression screenshots.
113 lines
4.1 KiB
JavaScript
113 lines
4.1 KiB
JavaScript
'use strict'
|
||
|
||
const test = require('node:test')
|
||
const assert = require('node:assert/strict')
|
||
|
||
const M = require('../src/renderer/compact-config-model.js')
|
||
|
||
let _seq = 0
|
||
function nextSeq() { _seq += 1; return _seq }
|
||
function reset() { _seq = 0 }
|
||
|
||
function userMsg(text = 'hi') {
|
||
return { type: 'user/message', seq: nextSeq(), data: { content: [{ type: 'text', text }] } }
|
||
}
|
||
function assistantMsg(text = 'ok', usage = null) {
|
||
const ev = { type: 'assistant/message', seq: nextSeq(), data: { content: [{ type: 'text', text }] } }
|
||
if (usage) ev.data.usage = usage
|
||
return ev
|
||
}
|
||
function compact(model = 'deepseek-chat', maxTokens = 512) {
|
||
return {
|
||
type: 'compact/summary',
|
||
seq: nextSeq(),
|
||
data: { summary: [{ type: 'text', text: 's' }], model, maxTokens, shadowedTokenCount: 8000 },
|
||
}
|
||
}
|
||
|
||
test('resolveThreshold: explicit override → server source', () => {
|
||
const r = M.resolveThreshold({ thresholdTokens: 50000 })
|
||
assert.equal(r.tokens, 50000)
|
||
assert.equal(r.source, 'server')
|
||
})
|
||
|
||
test('resolveThreshold: budget → 0.75 × budget, assumed source', () => {
|
||
const r = M.resolveThreshold({ budgetTokens: 128000 })
|
||
assert.equal(r.tokens, 96000)
|
||
assert.equal(r.source, 'assumed')
|
||
})
|
||
|
||
test('resolveThreshold: no info → default 96000', () => {
|
||
const r = M.resolveThreshold({})
|
||
assert.equal(r.tokens, M.DEFAULT_THRESHOLD_TOKENS)
|
||
assert.equal(r.source, 'assumed')
|
||
})
|
||
|
||
test('buildCompactConfigView: counts triggersFired from compact events', () => {
|
||
reset()
|
||
const events = [userMsg(), assistantMsg(), compact(), userMsg(), assistantMsg(), compact()]
|
||
const view = M.buildCompactConfigView(events)
|
||
assert.equal(view.triggersFired, 2)
|
||
})
|
||
|
||
test('buildCompactConfigView: lastCompactSeq points at final compact event', () => {
|
||
reset()
|
||
const events = [userMsg(), compact(), userMsg(), assistantMsg()]
|
||
const cLast = compact()
|
||
events.push(cLast)
|
||
const view = M.buildCompactConfigView(events)
|
||
assert.equal(view.lastCompactSeq, cLast.seq)
|
||
})
|
||
|
||
test('buildCompactConfigView: tokensSinceLastCompact resets on compact', () => {
|
||
reset()
|
||
const events = [userMsg('x'.repeat(4000)), compact(), userMsg('y'.repeat(400))]
|
||
const view = M.buildCompactConfigView(events)
|
||
assert.ok(view.tokensSinceLastCompact < 500, 'reset means we count only tokens after the compact')
|
||
assert.ok(view.tokensSinceLastCompact > 0, 'post-compact user msg still counted')
|
||
})
|
||
|
||
test('buildCompactConfigView: progressPct + level scale with threshold', () => {
|
||
reset()
|
||
const bigMsg = { type: 'user/message', seq: nextSeq(), data: { content: [{ type: 'text', text: 'x'.repeat(400000) }] } }
|
||
const view = M.buildCompactConfigView([bigMsg], { thresholdTokens: 96000 })
|
||
assert.ok(view.progressPct >= 95, `expected critical level, got ${view.progressPct}%`)
|
||
assert.equal(view.progressLevel, 'critical')
|
||
})
|
||
|
||
test('buildCompactConfigView: tokensUntilNext floors at 0', () => {
|
||
reset()
|
||
const bigMsg = { type: 'user/message', seq: nextSeq(), data: { content: [{ type: 'text', text: 'x'.repeat(500000) }] } }
|
||
const view = M.buildCompactConfigView([bigMsg], { thresholdTokens: 96000 })
|
||
assert.equal(view.tokensUntilNext, 0)
|
||
})
|
||
|
||
test('buildCompactConfigView: empty events → zeroed view', () => {
|
||
const view = M.buildCompactConfigView([])
|
||
assert.equal(view.triggersFired, 0)
|
||
assert.equal(view.currentTokens, 0)
|
||
assert.equal(view.lastCompactSeq, null)
|
||
assert.equal(view.progressLevel, 'nominal')
|
||
})
|
||
|
||
test('buildCompactConfigView: strategy override wins over inferred default', () => {
|
||
const view = M.buildCompactConfigView([], { strategyName: 'sliding-window' })
|
||
assert.equal(view.strategyName, 'sliding-window')
|
||
})
|
||
|
||
test('buildCompactConfigView: last policy carries model + maxSummaryTokens', () => {
|
||
reset()
|
||
const events = [compact('deepseek-chat-v3', 1024)]
|
||
const view = M.buildCompactConfigView(events)
|
||
assert.equal(view.model, 'deepseek-chat-v3')
|
||
assert.equal(view.maxSummaryTokens, 1024)
|
||
})
|
||
|
||
test('levelForPct thresholds', () => {
|
||
assert.equal(M.levelForPct(0), 'nominal')
|
||
assert.equal(M.levelForPct(49), 'nominal')
|
||
assert.equal(M.levelForPct(50), 'warn')
|
||
assert.equal(M.levelForPct(80), 'high')
|
||
assert.equal(M.levelForPct(95), 'critical')
|
||
})
|