fix(host): keep metrics route lookup passive (round 3)
This commit is contained in:
@@ -6,8 +6,8 @@
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Context } from 'cordis'
|
||||
import AgentRegistry, { agentEvents } from '@deepseek-ai/dsh-agent'
|
||||
import type { Agent } from '@deepseek-ai/dsh-agent'
|
||||
import AgentRegistry, { agentEvents, installAgentLlmTarget } from '@deepseek-ai/dsh-agent'
|
||||
import type { Agent, AgentLlmTargetRef } from '@deepseek-ai/dsh-agent'
|
||||
import LlmService, { LlmAdapter, ReasoningEffortId } from '@deepseek-ai/dsh-llm'
|
||||
import type {
|
||||
GenerateOptions, LlmCallConfig, LlmModelInfo, LlmModelReasoningInfo, LlmProviderInfo,
|
||||
@@ -72,15 +72,7 @@ const REASONING: LlmModelReasoningInfo = {
|
||||
defaultEffort: ReasoningEffortId('high'),
|
||||
}
|
||||
|
||||
async function harness(logged?: {
|
||||
provider: string
|
||||
model: string
|
||||
reasoningEffort?: ReasoningEffortId
|
||||
}): Promise<{
|
||||
ctx: Context
|
||||
agent: Agent
|
||||
sessionId: SessionId
|
||||
}> {
|
||||
async function hostContext(): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(SessionStore)
|
||||
await ctx.plugin(SystemPrompt, { persona: '' })
|
||||
@@ -100,6 +92,19 @@ async function harness(logged?: {
|
||||
{ provider: 'duplicate', id: 'same', name: 'Same' },
|
||||
{ provider: 'duplicate', id: 'same', name: 'Same Again' },
|
||||
]))
|
||||
return ctx
|
||||
}
|
||||
|
||||
async function harness(logged?: {
|
||||
provider: string
|
||||
model: string
|
||||
reasoningEffort?: ReasoningEffortId
|
||||
}): Promise<{
|
||||
ctx: Context
|
||||
agent: Agent
|
||||
sessionId: SessionId
|
||||
}> {
|
||||
const ctx = await hostContext()
|
||||
const session = ctx.sessions.create()
|
||||
if (logged !== undefined) {
|
||||
session.append('request/header', { header: { config: logged }, reason: 'initial' })
|
||||
@@ -246,6 +251,7 @@ describe('Web session model selection', () => {
|
||||
it('publishes unknown capacity immediately on selection, then the exact selected route capacity', async () => {
|
||||
const { ctx, sessionId } = await harness()
|
||||
const api = createApiProxy(ctx, { provider: 'deepseek', model: 'deepseek-chat', cwd: '/tmp', workspaceRoot: '/tmp' })
|
||||
expectValue(await api.sessions.models(request({ sessionId })))
|
||||
const controller = new AbortController()
|
||||
const iterator = api.events.mux(request({}), controller.signal)[Symbol.asyncIterator]()
|
||||
|
||||
@@ -264,4 +270,56 @@ describe('Web session model selection', () => {
|
||||
await iterator.return?.()
|
||||
await ctx.fiber.dispose()
|
||||
})
|
||||
|
||||
it('uses logged capacity without installing Web routing while scheduling foreign metrics', async () => {
|
||||
const ctx = await hostContext()
|
||||
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]()
|
||||
const initialMetrics = nextMetrics(iterator)
|
||||
const session = ctx.sessions.create()
|
||||
expect((await initialMetrics).contextWindow).toBeUndefined()
|
||||
session.append('request/header', {
|
||||
header: { config: { provider: 'deepseek', model: 'private-preview' } },
|
||||
reason: 'change',
|
||||
})
|
||||
const foreign = {
|
||||
id: session.id,
|
||||
session,
|
||||
status: 'running',
|
||||
ctx,
|
||||
} as Agent
|
||||
const foreignTarget: AgentLlmTargetRef = {
|
||||
current: { provider: 'foreign', model: 'foreign-model' },
|
||||
assembled: undefined,
|
||||
}
|
||||
const disposeForeignTarget = installAgentLlmTarget(foreign.ctx, foreignTarget)
|
||||
const scheduledMetrics = nextMetrics(iterator)
|
||||
ctx.agents.register(foreign)
|
||||
|
||||
expect((await scheduledMetrics).contextWindow).toBeUndefined()
|
||||
expect((await nextMetrics(iterator)).contextWindow).toBe(128_000)
|
||||
expect((await ctx.systemPrompt.assemble()).variables)
|
||||
.toMatchObject({ provider: 'foreign', model: 'foreign-model' })
|
||||
const seed: LlmCallConfig = { provider: 'seed', model: 'seed', temperature: 0.2 }
|
||||
const signal = new AbortController().signal
|
||||
await expect(agentEvents(ctx, foreign).waterfall(
|
||||
'agent/request', 1, 0, signal, () => Promise.resolve(seed),
|
||||
)).resolves.toMatchObject({ provider: 'foreign', model: 'foreign-model' })
|
||||
|
||||
disposeForeignTarget()
|
||||
expect((await ctx.systemPrompt.assemble()).variables).not.toHaveProperty('provider')
|
||||
await expect(agentEvents(ctx, foreign).waterfall(
|
||||
'agent/request', 1, 1, signal, () => Promise.resolve(seed),
|
||||
)).resolves.toBe(seed)
|
||||
|
||||
controller.abort()
|
||||
await iterator.return?.()
|
||||
await ctx.fiber.dispose()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -187,6 +187,37 @@ describe('SessionMetricsProjector', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('starts a fresh capacity generation when an unavailable route returns', async () => {
|
||||
const ctx = new Context()
|
||||
const resolutions: ((contextWindow: number) => void)[] = []
|
||||
ctx.provide('llm', {
|
||||
resolveModelInfo() {
|
||||
return new Promise<{ context: { contextWindow: number } }>((resolve) => {
|
||||
resolutions.push((contextWindow) => { resolve({ context: { contextWindow } }) })
|
||||
})
|
||||
},
|
||||
})
|
||||
const session = new Session(SessionId('capacity-route-return'))
|
||||
const attached = agent(session)
|
||||
let current: AgentLlmTarget | undefined = { provider: 'test', model: 'alpha' }
|
||||
const resolved = vi.fn()
|
||||
const targetFor = vi.fn(() => current)
|
||||
const projector = new SessionMetricsProjector(ctx, targetFor, resolved)
|
||||
|
||||
expect(projector.snapshot(session, attached).contextWindow).toBeUndefined()
|
||||
await vi.waitFor(() => { expect(resolutions).toHaveLength(1) })
|
||||
current = undefined
|
||||
resolutions[0]?.(64_000)
|
||||
await vi.waitFor(() => { expect(targetFor).toHaveBeenCalledTimes(2) })
|
||||
expect(resolved).not.toHaveBeenCalled()
|
||||
current = { provider: 'test', model: 'alpha' }
|
||||
expect(projector.snapshot(session, attached).contextWindow).toBeUndefined()
|
||||
await vi.waitFor(() => { expect(resolutions).toHaveLength(2) })
|
||||
resolutions[1]?.(128_000)
|
||||
await vi.waitFor(() => { expect(resolved).toHaveBeenCalledOnce() })
|
||||
expect(projector.snapshot(session, attached).contextWindow).toBe(128_000)
|
||||
})
|
||||
|
||||
it('omits current context fields when measurement or model metadata is unavailable', async () => {
|
||||
const ctx = new Context()
|
||||
ctx.provide('tokenMeter', { measure: () => { throw new Error('unmeasurable') } })
|
||||
@@ -211,9 +242,10 @@ describe('SessionMetricsProjector', () => {
|
||||
const session = new Session(SessionId('optional-metrics'))
|
||||
assistant(session, 1, 0, { inputTokens: 7, outputTokens: 2 })
|
||||
const attached = agent(session)
|
||||
const selected: { current?: AgentLlmTarget } = {}
|
||||
const projector = new SessionMetricsProjector(
|
||||
ctx,
|
||||
() => ({ provider: 'test', model: 'no-service' }),
|
||||
() => selected.current,
|
||||
() => {},
|
||||
)
|
||||
|
||||
@@ -224,6 +256,7 @@ describe('SessionMetricsProjector', () => {
|
||||
cacheWriteTokens: 0,
|
||||
})
|
||||
expect(projector.snapshot(session, attached).contextWindow).toBeUndefined()
|
||||
selected.current = { provider: 'test', model: 'no-service' }
|
||||
expect(projector.snapshot(session, attached).contextWindow).toBeUndefined()
|
||||
await Promise.resolve()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user