fix(host): guard terminal metric snapshots (round 6 review)
This commit is contained in:
@@ -422,7 +422,7 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
|
|||||||
|
|
||||||
/** Pair a registry agent only with the exact Session lifecycle it owns. */
|
/** Pair a registry agent only with the exact Session lifecycle it owns. */
|
||||||
function metricsAgentFor(session: Session): Agent | undefined {
|
function metricsAgentFor(session: Session): Agent | undefined {
|
||||||
const agent = ctx.agents.get(session.id)
|
const agent = ctx.get('agents')?.get(session.id)
|
||||||
return agent?.session === session ? agent : undefined
|
return agent?.session === session ? agent : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -619,6 +619,49 @@ describe('Web session model selection', () => {
|
|||||||
await ctx.fiber.dispose()
|
await ctx.fiber.dispose()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('publishes unknown metrics after AgentRegistry terminal disposal with mux active', async () => {
|
||||||
|
let agentsFiber: Fiber | undefined
|
||||||
|
const ctx = await hostContext(undefined, (fiber) => { agentsFiber = fiber })
|
||||||
|
if (agentsFiber === undefined) throw new Error('agent registry fiber missing')
|
||||||
|
const deferred = new DeferredCatalogAdapter()
|
||||||
|
ctx.llm.registerAdapter(['deferred'], deferred)
|
||||||
|
const lifecycle = attachLifecycleSession(ctx, SessionId('capacity-agent-registry-disposed'))
|
||||||
|
const detachAgent = attachLifecycleAgent(ctx, lifecycle.session)
|
||||||
|
const api = createApiProxy(ctx, { provider: 'deepseek', model: 'deepseek-chat', cwd: '/tmp', workspaceRoot: '/tmp' })
|
||||||
|
const controller = new AbortController()
|
||||||
|
const iterator = api.events.mux(request({}), controller.signal)[Symbol.asyncIterator]()
|
||||||
|
|
||||||
|
expect((await nextMetrics(iterator)).contextWindow).toBeUndefined()
|
||||||
|
await vi.waitFor(() => { expect(deferred.pending).toHaveLength(1) })
|
||||||
|
deferred.resolve(0, 64_000)
|
||||||
|
await settleCapacityCompletion()
|
||||||
|
expect((await nextMetrics(iterator)).contextWindow).toBe(64_000)
|
||||||
|
|
||||||
|
await agentsFiber.dispose()
|
||||||
|
const refresh = nextMetrics(iterator).then(
|
||||||
|
metrics => ({ kind: 'metrics' as const, metrics }),
|
||||||
|
() => ({ kind: 'error' as const }),
|
||||||
|
)
|
||||||
|
const outcome = await Promise.race([
|
||||||
|
refresh,
|
||||||
|
new Promise<{ kind: 'idle' }>((resolve) => {
|
||||||
|
setImmediate(() => { resolve({ kind: 'idle' }) })
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
controller.abort()
|
||||||
|
await refresh
|
||||||
|
await iterator.return?.()
|
||||||
|
detachAgent()
|
||||||
|
lifecycle.detach()
|
||||||
|
await ctx.fiber.dispose()
|
||||||
|
expect(outcome.kind).toBe('metrics')
|
||||||
|
if (outcome.kind === 'metrics') {
|
||||||
|
expect(outcome.metrics.contextWindow).toBeUndefined()
|
||||||
|
expect(outcome.metrics.logRevision).toBe(1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
it.each(['agents', 'sessions'] as const)(
|
it.each(['agents', 'sessions'] as const)(
|
||||||
'drops capacity completion while %s is unavailable during unload',
|
'drops capacity completion while %s is unavailable during unload',
|
||||||
async (serviceName) => {
|
async (serviceName) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user