refactor(token-meter): make context occupancy durable projection state

Replace the transient `session/model-request` mux frame with ordinary durable
session state. Occupancy now rides two last-wins projection fields instead of a
non-replayable frame that needed removal tombstones and cross-stream fencing.

The frame was the only non-replayable class on the mux stream. Because host and
mux are independent SSE streams with no cross-stream order, a request emitted
before a removal could arrive after `host/session-removed`, and a legitimate
request for a new lifecycle reusing the same id could be fenced by a late
removal. Fixing that needed a lifecycle generation on every frame; the frame
itself was the problem.

Removed: the `session/model-request` frame and schema, the `agent/model-request`
core event, the ApiProxy measurement point, the client-side telemetry map and
removal tombstone, and the synthetic `cancelled` open error used to signal
reconnect through the error channel.

Added: `request/context`, a log-only session event recording the
registration-bound capacity of the route a request resolved to, appended beside
`request/header` from the lookup that already prepared the call and skipped when
the route is unchanged. Capacity stays out of `EpochHeader` because it is
adapter metadata about a route, not an input the request was built from, so it
must not join request reconstruction or header equality.

The `contextPressure` projection pairs the newest provider-reported prompt size
with the newest recorded capacity. The two are deliberately not one atomic
request observation: switching models can pair a fresh capacity with the prior
route's pressure until the next request reports usage. The figure is a
user-facing reference, and this matches how the TUI status line has always
computed occupancy.
This commit is contained in:
Hypatia May
2026-07-30 13:53:08 +08:00
parent fdccc58cef
commit 4819210142
62 changed files with 382 additions and 1362 deletions

View File

@@ -41,228 +41,6 @@ describe('instances', () => {
expect(manager.get(S2).getSnapshot().pending).toEqual([])
})
it('retains the latest transient request snapshot until lazy instantiation', () => {
const api = new FakeApiClient()
const manager = new SessionManager(api)
manager.handleMuxEnvelope({
rpcId: 'request-1' as never,
payload: {
type: 'session/model-request',
sessionId: S1,
turn: 1,
step: 1,
provider: 'test',
model: 'alpha',
contextTokens: 12_000,
contextWindow: 128_000,
},
})
manager.handleMuxEnvelope({
rpcId: 'request-2' as never,
payload: {
type: 'session/model-request',
sessionId: S1,
turn: 1,
step: 2,
provider: 'test',
model: 'beta',
contextTokens: 32_000,
contextWindow: 256_000,
},
})
expect(manager.get(S1).getSnapshot().modelRequest).toEqual({
turn: 1,
step: 2,
provider: 'test',
model: 'beta',
contextTokens: 32_000,
contextWindow: 256_000,
})
})
it('retains whole-frame replacement before lazy instantiation', () => {
const api = new FakeApiClient()
const manager = new SessionManager(api)
manager.handleMuxEnvelope({
rpcId: 'request-with-capacity' as never,
payload: {
type: 'session/model-request',
sessionId: S1,
turn: 1,
step: 1,
provider: 'test',
model: 'alpha',
contextWindow: 128_000,
},
})
manager.handleMuxEnvelope({
rpcId: 'request-without-capacity' as never,
payload: {
type: 'session/model-request',
sessionId: S1,
turn: 1,
step: 2,
provider: 'test',
model: 'unknown-capacity',
},
})
expect(manager.get(S1).getSnapshot().modelRequest).toEqual({
turn: 1,
step: 2,
provider: 'test',
model: 'unknown-capacity',
})
})
it('clears retained request telemetry on subscribed and removal', () => {
const api = new FakeApiClient()
const manager = new SessionManager(api)
manager.handleMuxEnvelope({
rpcId: 'request-before-subscribe' as never,
payload: {
type: 'session/model-request',
sessionId: S1,
turn: 1,
step: 1,
provider: 'test',
model: 'alpha',
contextWindow: 128_000,
},
})
manager.handleMuxEnvelope({
rpcId: 'subscribed' as never,
payload: { type: 'session/subscribed', sessionId: S1, lastSeq: 0 },
})
const session = manager.get(S1)
expect(session.getSnapshot().modelRequest).toBeNull()
manager.handleMuxEnvelope({
rpcId: 'request-after-subscribe' as never,
payload: {
type: 'session/model-request',
sessionId: S1,
turn: 1,
step: 2,
provider: 'test',
model: 'beta',
contextWindow: 256_000,
},
})
expect(session.getSnapshot().modelRequest?.contextWindow).toBe(256_000)
manager.handleHostEnvelope({
rpcId: 'removed' as never,
payload: { type: 'host/session-removed', sessionId: S1 },
})
expect(session.getSnapshot().modelRequest).toBeNull()
manager.handleMuxEnvelope({
rpcId: 'late-resident-request' as never,
payload: {
type: 'session/model-request',
sessionId: S1,
turn: 2,
step: 1,
provider: 'test',
model: 'late',
contextWindow: 512_000,
},
})
expect(session.getSnapshot().modelRequest).toBeNull()
manager.handleMuxEnvelope({
rpcId: 'resumed-subscription' as never,
payload: { type: 'session/subscribed', sessionId: S1, lastSeq: 0 },
})
manager.handleMuxEnvelope({
rpcId: 'resumed-request' as never,
payload: {
type: 'session/model-request',
sessionId: S1,
turn: 1,
step: 1,
provider: 'test',
model: 'resumed',
contextWindow: 256_000,
},
})
expect(session.getSnapshot().modelRequest).toMatchObject({
model: 'resumed',
contextWindow: 256_000,
})
manager.handleMuxEnvelope({
rpcId: 'request-before-lazy-removal' as never,
payload: {
type: 'session/model-request',
sessionId: S2,
turn: 1,
step: 1,
provider: 'test',
model: 'gamma',
contextWindow: 64_000,
},
})
manager.handleHostEnvelope({
rpcId: 'lazy-removed' as never,
payload: { type: 'host/session-removed', sessionId: S2 },
})
manager.handleMuxEnvelope({
rpcId: 'late-lazy-request' as never,
payload: {
type: 'session/model-request',
sessionId: S2,
turn: 2,
step: 1,
provider: 'test',
model: 'late-lazy',
contextWindow: 512_000,
},
})
expect(manager.get(S2).getSnapshot().modelRequest).toBeNull()
})
it('clears resident and lazy request telemetry on disconnect', () => {
const api = new FakeApiClient()
const manager = new SessionManager(api)
const session = manager.get(S1)
manager.handleMuxEnvelope({
rpcId: 'resident-request' as never,
payload: {
type: 'session/model-request',
sessionId: S1,
turn: 1,
step: 1,
provider: 'test',
model: 'resident',
contextTokens: 35,
contextWindow: 128_000,
},
})
manager.handleMuxEnvelope({
rpcId: 'lazy-request' as never,
payload: {
type: 'session/model-request',
sessionId: S2,
turn: 1,
step: 1,
provider: 'test',
model: 'lazy',
contextTokens: 70,
contextWindow: 256_000,
},
})
expect(session.getSnapshot().modelRequest).toMatchObject({
model: 'resident',
contextTokens: 35,
contextWindow: 128_000,
})
manager.handleDisconnected()
expect(session.getSnapshot().modelRequest).toBeNull()
expect(manager.get(S2).getSnapshot().modelRequest).toBeNull()
})
it('caps the pending buffer at 32 keeping the newest, and drops it on session-removed', () => {
const api = new FakeApiClient()
const manager = new SessionManager(api)