Apply the full-repo comment audit to the host half and shared wire types: delete restatements and decorative headers, compress rationale comments to one line, and fix stale references (agent-loop buildRequest, live-surface image cell, five->four priced categories). Kept only contract notes, invariants (plain-JSON precondition, shadow-seqs protocol) and verified dsh-mirror pins.
300 lines
11 KiB
TypeScript
300 lines
11 KiB
TypeScript
/**
|
|
* Shared wire contract — the snapshot model exchanged between the Host and Client halves. Delivered as the `view()` payload of the
|
|
* `contextTimeline`/`contextHeaders` session projections (registered on `ctx.sessionProjections`; the registry pushes finished views as
|
|
* `session/projection` frames — see host/timeline.ts). TYPE-ONLY host-side module: both halves import these as `import type`, so nothing
|
|
* from here ever reaches the runtime bundles.
|
|
*/
|
|
|
|
import type {} from '@deepseek-ai/dsh-session-projection/types'
|
|
|
|
declare module '@deepseek-ai/dsh-session-projection/types' {
|
|
interface SessionProjectionMap {
|
|
/**
|
|
* The plugin's whole-value context timeline: current composition,
|
|
* per-request history, context events, and the model-visible surface.
|
|
* The Host folds it from the session log; clients receive the finished
|
|
* value (key absence = the plugin's host half is not composed).
|
|
*/
|
|
contextTimeline: ContextTimeline
|
|
/**
|
|
* The request-header CONTENT epochs (full system prompt + tool schemas)
|
|
* behind the timeline's envelope figures. A separate unit so the hot
|
|
* `contextTimeline` value stays lean: headers change rarely, so this
|
|
* value (and its pushes) change only when a `request/header` lands.
|
|
* The Context browser card reads it to show the actual prompt/schema
|
|
* content of a picked step (key absence = older host: tokens only).
|
|
*/
|
|
contextHeaders: ContextHeaders
|
|
}
|
|
}
|
|
|
|
export type Category = 'user' | 'inject' | 'assistant' | 'tool'
|
|
|
|
export interface Snapshot {
|
|
ok: boolean
|
|
model?: string
|
|
provider?: string
|
|
contextWindow?: number
|
|
current: {
|
|
system: number
|
|
tools: number
|
|
user: number
|
|
inject: number
|
|
assistant: number
|
|
tool: number
|
|
total: number
|
|
}
|
|
/**
|
|
* Provider-anchored occupancy of the NEXT request. LEGACY since 0.11: the
|
|
* Host no longer folds this — the Client reads the official token-meter
|
|
* `contextPressure` projection key (`useProjection('contextPressure')`)
|
|
* instead. Kept optional for wire compatibility with older clients.
|
|
*/
|
|
occupancy?: {
|
|
pressureTokens?: number
|
|
surfaceTokens: number
|
|
sampledSurfaceTokens?: number
|
|
projectedTokens?: number
|
|
contextWindow?: number
|
|
}
|
|
toolList: { name: string; tokens: number }[]
|
|
/**
|
|
* Image blocks live in the CURRENT context (user uploads plus tool-result
|
|
* images, nested blocks included) — the sum over the live surface nodes'
|
|
* `imgs`, so compaction/prune shrink it. Absent from older hosts; clients
|
|
* treat absence as zero.
|
|
*/
|
|
images?: number
|
|
/**
|
|
* Tool calls whose result is live in the CURRENT context (one `tool/result`
|
|
* folds to one `tool` surface node). Calls still in flight and results
|
|
* compacted/pruned out of the surface are not counted. Absent from older
|
|
* hosts; clients treat absence as zero.
|
|
*/
|
|
toolCalls?: number
|
|
requests: RequestRecord[]
|
|
events: ContextEventRecord[]
|
|
/**
|
|
* Cumulative session-cost raw material (per-family, per-period billed
|
|
* token totals — see SessionCostUsage). Absent until a DeepSeek V4
|
|
* request reports usage.
|
|
*/
|
|
cost?: SessionCostUsage
|
|
/**
|
|
* The served live surface: the newest `maxNodes` tail PLUS every live inject node older than the tail (injections land first and are
|
|
* few,
|
|
* so they are pinned). Seq-ordered, oldest first.
|
|
*/
|
|
nodes: SurfaceNode[]
|
|
/** Live nodes not served (the overflow beyond `maxNodes`, minus pinned injects — see `nodes`). */
|
|
droppedNodes: number
|
|
/**
|
|
* Recently REMOVED surface nodes (compaction/prune shadows), each stamped
|
|
* with `gone` (the replacing event's seq). Together with `nodes` this lets
|
|
* the Context browser reconstruct the assembled surface of any retained
|
|
* step: alive at request R = seq < R.seq && (gone undefined || gone > R.seq).
|
|
*/
|
|
archive: SurfaceNode[]
|
|
/**
|
|
* Coverage floor of the served live `nodes`: the newest seq among the
|
|
* `droppedNodes` live nodes not served. Present only when droppedNodes > 0.
|
|
*/
|
|
surfaceFloor?: number
|
|
/**
|
|
* Coverage floor of `archive`: the newest `gone` among archive entries the
|
|
* retention bounds dropped. Steps with seq < archiveFloor may miss removed
|
|
* nodes (the browser shows the reconstruction as approximate).
|
|
*/
|
|
archiveFloor?: number
|
|
}
|
|
|
|
/**
|
|
* The `contextTimeline` projection's whole value — the same snapshot the Client has always rendered. `ok` is always `true` here (a
|
|
* delivered projection is by definition available); kept for wire compatibility with the snapshot shape.
|
|
*/
|
|
export type ContextTimeline = Snapshot
|
|
|
|
/**
|
|
* The official token-meter `contextPressure` projection (registered by
|
|
* `@deepseek-ai/dsh-token-meter` on the same `SessionProjectionMap`): the
|
|
* provider-anchored occupancy of the NEXT request. The Client reads this key
|
|
* directly instead of the Host mirroring it inside `contextTimeline`
|
|
* (token-meter owns estimation and replay — the docs' stated division of
|
|
* labor). Fields are independent last-wins records; absent until a provider
|
|
* reports usage. Absent key/value = the registry (or the meter) is not
|
|
* composed — the Client falls back to its derived anchor.
|
|
*/
|
|
export interface ContextPressure {
|
|
/** Provider-reported prompt size of the most recent request (input + cache). */
|
|
pressureTokens?: number
|
|
/** pressureTokens + heuristic surface movement since the sample (clamped ≥ 0). */
|
|
projectedTokens?: number
|
|
/** Newest recorded route capacity (last-wins). */
|
|
contextWindow?: number
|
|
}
|
|
|
|
/**
|
|
* The official token-meter `contextBreakdown` projection: the heuristic
|
|
* composition rows the chat ring's click-open panel shows (system prompt,
|
|
* tool schemas, conversation). The Client reads this key directly so the
|
|
* composition card's proportions AND counts stay identical to the panel's
|
|
* by construction; the message bucket is subdivided into the plugin's four
|
|
* surface categories by the fold's per-category ratios. Absent key/value =
|
|
* an older harness without the meter's projection units — callers fall back
|
|
* to the fold's own sums (identical estimator, minus the image correction).
|
|
*/
|
|
export interface ContextBreakdown {
|
|
systemTokens: number
|
|
toolsTokens: number
|
|
messageTokens: number
|
|
}
|
|
|
|
/**
|
|
* The official token-meter `tokenUsage` projection (registered by
|
|
* `@deepseek-ai/dsh-token-meter` on the same `SessionProjectionMap`): durable
|
|
* cumulative provider-reported usage across the COMPLETE session log. The four
|
|
* buckets are disjoint (reasoning tokens are already inside `outputTokens`).
|
|
* The Client reads this key directly to compute the cache-hit share — the
|
|
* exact same data the chat stats line below the input box shows, same formula
|
|
* — instead of the Host mirroring it inside `contextTimeline`. Absent until a
|
|
* provider reports usage.
|
|
*/
|
|
export interface TokenUsage {
|
|
/** Billed prompt tokens that missed the provider cache. */
|
|
uncachedInputTokens: number
|
|
/** Billed output tokens (reasoning included). */
|
|
outputTokens: number
|
|
/** Billed prompt tokens served from the provider cache. */
|
|
cacheReadTokens: number
|
|
/** Billed prompt tokens written into the provider cache. */
|
|
cacheWriteTokens: number
|
|
}
|
|
|
|
/**
|
|
* Cumulative billed-token totals for one pricing bucket of the session-cost
|
|
* estimate (host-folded, never trimmed — running totals over the COMPLETE
|
|
* session log, immune to the request/event retention bounds).
|
|
*/
|
|
export interface CostBucketTotals {
|
|
uncached: number
|
|
cacheRead: number
|
|
cacheWrite: number
|
|
output: number
|
|
}
|
|
|
|
/** One model family's totals split by DeepSeek's pricing period (Beijing Time). */
|
|
export interface CostFamilyUsage {
|
|
peak?: CostBucketTotals
|
|
off?: CostBucketTotals
|
|
}
|
|
|
|
/**
|
|
* The session-cost estimate's raw material: cumulative provider-reported
|
|
* token totals per DeepSeek V4 model family (matched on the model NAME,
|
|
* provider-agnostic) and pricing period. The Client prices these with its
|
|
* hardcoded list-price table in the locale's currency. Absent until a
|
|
* deepseek-v4-flash / deepseek-v4-pro request reports usage.
|
|
*/
|
|
export interface SessionCostUsage {
|
|
flash?: CostFamilyUsage
|
|
pro?: CostFamilyUsage
|
|
}
|
|
|
|
/** One model-visible message on the surface, with its heuristic token price. */
|
|
export interface SurfaceNode {
|
|
seq: number
|
|
time?: number
|
|
cat: Category
|
|
tokens: number
|
|
/** Image blocks inside this node's message (absent when zero). */
|
|
imgs?: number
|
|
/**
|
|
* Removal marker, present only on `archive` entries: the seq of the
|
|
* replacement surface event that shadowed this node (compaction/prune).
|
|
* The node is part of the assembled context of every request with
|
|
* seq > this node.seq and seq < gone.
|
|
*/
|
|
gone?: number
|
|
form?: string
|
|
text?: string
|
|
tool?: string
|
|
err?: boolean
|
|
skill?: string
|
|
calls?: string[]
|
|
}
|
|
|
|
/** One answered model call (a step); consecutive records of one turn form it. */
|
|
export interface RequestRecord {
|
|
turn?: number
|
|
step?: number
|
|
time: number
|
|
seq: number
|
|
system: number
|
|
tools: number
|
|
user: number
|
|
inject: number
|
|
assistant: number
|
|
tool: number
|
|
total: number
|
|
prompt?: number
|
|
output?: number
|
|
/**
|
|
* Turn-mode aggregate marker, set by the Client's aggregateByTurn (one bar
|
|
* per turn shows its LAST step's record). The Host never sets it.
|
|
*/
|
|
stepCount?: number
|
|
/**
|
|
* Diff-mode signed net change, set by the Client's diffOf (only present
|
|
* on the diff-transformed records the TrendChart plots). The Host never
|
|
* sets it.
|
|
*/
|
|
net?: number
|
|
}
|
|
|
|
/** A notable context event (compaction, prune, injection, model switch). */
|
|
export interface ContextEventRecord {
|
|
seq: number
|
|
time: number
|
|
kind: 'compaction' | 'prune' | 'inject' | 'model' | 'mode'
|
|
form?: string
|
|
tokens?: number
|
|
count?: number
|
|
sub?: string
|
|
name?: string
|
|
/** One-line producer account (notice-form summary), shown after the name. */
|
|
detail?: string
|
|
from?: string
|
|
to?: string
|
|
/** Turn/step of the request logged right BEFORE the event (host-stamped). */
|
|
fromTurn?: number
|
|
fromStep?: number
|
|
/** Turn/step of the request this event contributed to (host-stamped). */
|
|
turn?: number
|
|
step?: number
|
|
}
|
|
|
|
/** One tool schema as assembled into a request header, with its display price. */
|
|
export interface HeaderTool {
|
|
name: string
|
|
tokens: number
|
|
/** Producer-declared description (may be long; the browser truncates). */
|
|
description?: string
|
|
/** The raw JSON schema object the model received (plain JSON). */
|
|
schema?: unknown
|
|
}
|
|
|
|
/**
|
|
* One request-header epoch: the full system prompt and tool schemas in force from this event's seq until the next epoch.
|
|
*/
|
|
export interface HeaderRecord {
|
|
seq: number
|
|
time: number
|
|
system?: string
|
|
tools: HeaderTool[]
|
|
}
|
|
|
|
/** The `contextHeaders` projection value: the bounded epoch list (newest last). */
|
|
export interface ContextHeaders {
|
|
headers: HeaderRecord[]
|
|
}
|