fix(host): refresh metric capacity metadata (round 6)
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
import { randomUUID } from 'node:crypto'
|
||||
import { mkdir, stat } from 'node:fs/promises'
|
||||
import { join } from 'node:path'
|
||||
import { FiberState } from 'cordis'
|
||||
import type { Context } from 'cordis'
|
||||
import { installAgentLlmTarget } from '@deepseek-ai/dsh-agent'
|
||||
import type {
|
||||
@@ -483,6 +484,16 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
||||
}),
|
||||
ctx.on('agent/created', (agent: Agent) => { scheduleMetrics(agent.session) }),
|
||||
ctx.on('session/disposed', (session: Session) => { pendingMetricSessions.delete(session) }),
|
||||
ctx.on('internal/status', (fiber) => {
|
||||
if (metricsDisposed) return
|
||||
if (fiber.state !== FiberState.ACTIVE
|
||||
&& fiber.state !== FiberState.FAILED
|
||||
&& fiber.state !== FiberState.DISPOSED) return
|
||||
const sessions = ctx.get('sessions')
|
||||
if (sessions === undefined) return
|
||||
metricsProjector.invalidateCapacities()
|
||||
for (const session of sessions.list()) scheduleMetrics(session)
|
||||
}, { global: true }),
|
||||
]
|
||||
return () => {
|
||||
metricsDisposed = true
|
||||
|
||||
@@ -23,7 +23,8 @@ interface UsageState {
|
||||
interface CapacityState {
|
||||
routeKey: string | undefined
|
||||
generation: number
|
||||
status: 'pending' | 'ready'
|
||||
epoch: number
|
||||
status: 'pending' | 'ready' | 'retryable'
|
||||
contextWindow?: number
|
||||
}
|
||||
|
||||
@@ -88,6 +89,7 @@ function routeKeyFor(target: CapacityTarget | undefined): string | undefined {
|
||||
export class SessionMetricsProjector {
|
||||
private readonly usage = new WeakMap<Session, UsageState>()
|
||||
private readonly capacities = new WeakMap<Agent, CapacityState>()
|
||||
private capacityEpoch = 0
|
||||
|
||||
/**
|
||||
* @param ctx - Host context providing optional token-meter and LLM services.
|
||||
@@ -100,6 +102,11 @@ export class SessionMetricsProjector {
|
||||
private readonly onCapacityResolved: (agent: Agent) => void,
|
||||
) {}
|
||||
|
||||
/** Retire adapter-owned metadata and fence every resolution already in flight. */
|
||||
invalidateCapacities(): void {
|
||||
this.capacityEpoch++
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a fresh detached projection through the session's durable tail.
|
||||
* @param session - authoritative durable log owner.
|
||||
@@ -159,10 +166,14 @@ export class SessionMetricsProjector {
|
||||
const target = this.targetFor(agent)
|
||||
const routeKey = routeKeyFor(target)
|
||||
let state = this.capacities.get(agent)
|
||||
if (state === undefined || state.routeKey !== routeKey) {
|
||||
if (state === undefined
|
||||
|| state.routeKey !== routeKey
|
||||
|| state.epoch !== this.capacityEpoch
|
||||
|| state.status === 'retryable') {
|
||||
state = {
|
||||
routeKey,
|
||||
generation: (state?.generation ?? 0) + 1,
|
||||
epoch: this.capacityEpoch,
|
||||
status: target === undefined ? 'ready' : 'pending',
|
||||
}
|
||||
this.capacities.set(agent, state)
|
||||
@@ -178,7 +189,7 @@ export class SessionMetricsProjector {
|
||||
): void {
|
||||
const llm = this.ctx.get('llm') as LlmLike | undefined
|
||||
if (llm === undefined) {
|
||||
pending.status = 'ready'
|
||||
pending.status = 'retryable'
|
||||
return
|
||||
}
|
||||
void Promise.resolve()
|
||||
@@ -191,12 +202,13 @@ export class SessionMetricsProjector {
|
||||
this.onCapacityResolved(agent)
|
||||
},
|
||||
() => {
|
||||
if (!this.capacityResolutionIsStale(agent, pending)) pending.status = 'ready'
|
||||
if (!this.capacityResolutionIsStale(agent, pending)) pending.status = 'retryable'
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private capacityResolutionIsStale(agent: Agent, pending: CapacityState): boolean {
|
||||
if (pending.epoch !== this.capacityEpoch) return true
|
||||
if (this.capacities.get(agent)?.generation !== pending.generation) return true
|
||||
if (routeKeyFor(this.targetFor(agent)) === pending.routeKey) return false
|
||||
// Unknown is the neutral generation; the next observed concrete route
|
||||
@@ -204,6 +216,7 @@ export class SessionMetricsProjector {
|
||||
this.capacities.set(agent, {
|
||||
routeKey: undefined,
|
||||
generation: pending.generation + 1,
|
||||
epoch: this.capacityEpoch,
|
||||
status: 'ready',
|
||||
})
|
||||
return true
|
||||
|
||||
Reference in New Issue
Block a user