fix(web): address request telemetry review

This commit is contained in:
Hypatia May
2026-07-29 16:42:36 +08:00
parent 06f161a8c6
commit 840e5eaa40
12 changed files with 71 additions and 42 deletions

View File

@@ -66,6 +66,7 @@
"devDependencies": {
"@deepseek-ai/dsh-storage": "workspace:^",
"@deepseek-ai/dsh-storage-domain": "workspace:^",
"@deepseek-ai/dsh-token-meter": "workspace:^",
"cordis": "^4.0.0-rc.7",
"@deepseek-ai/dsh-invariants": "workspace:^"
}

View File

@@ -32,6 +32,8 @@ import type {
import type {} from '@deepseek-ai/dsh-session-projection'
// Type-only: resolves `ctx.get('sessionProjectionCache')` (the cold listing column).
import type {} from '@deepseek-ai/dsh-session-projection-cache'
// Type-only: resolves the optional `ctx.get('tokenMeter')` service seam.
import type {} from '@deepseek-ai/dsh-token-meter'
// GoalError narrows domain rejections to their stable codes at the wire boundary.
import { GoalError } from '@deepseek-ai/dsh-goal'
import type { GoalRef as CoreGoalRef } from '@deepseek-ai/dsh-goal'
@@ -495,34 +497,30 @@ export function createApiProxy(ctx: Context, defaults: ApiProxyDefaults): ApiPro
for (const queue of muxQueues) queue.push(envelope)
}
ctx.effect(() => {
return ctx.on('agent/model-request', (agent, turn, step, request) => {
const tokenMeter = ctx.get('tokenMeter') as {
measure(session: Session): { totalTokens: number }
} | undefined
let contextTokens: number | undefined
if (tokenMeter !== undefined) {
try {
contextTokens = tokenMeter.measure(agent.session).totalTokens
} catch {
// A malformed or temporarily unmeasurable replay omits only the
// numerator; this request still replaces stale telemetry.
}
ctx.on('agent/model-request', (agent, turn, step, request) => {
const tokenMeter = ctx.get('tokenMeter')
let contextTokens: number | undefined
if (tokenMeter !== undefined) {
try {
contextTokens = tokenMeter.measure(agent.session).totalTokens
} catch {
// A malformed or temporarily unmeasurable replay omits only the
// numerator; this request still replaces stale telemetry.
}
broadcast({
type: 'session/model-request',
sessionId: agent.session.id,
turn,
step,
provider: request.provider,
model: request.model,
...contextTokens === undefined ? {} : { contextTokens },
...request.contextWindow === undefined
? {}
: { contextWindow: request.contextWindow },
})
}
broadcast({
type: 'session/model-request',
sessionId: agent.session.id,
turn,
step,
provider: request.provider,
model: request.model,
...contextTokens === undefined ? {} : { contextTokens },
...request.contextWindow === undefined
? {}
: { contextWindow: request.contextWindow },
})
}, 'api-proxy: model request telemetry')
})
// Projection change feed → session/projection push frames. The carrier
// mints the wire frame (the seam package holds no wire vocabulary); the

View File

@@ -41,7 +41,7 @@ export const muxFrameSchema = z.discriminatedUnion('type', [
type: z.literal('session/model-request'),
sessionId: sessionIdSchema,
turn: z.number().int().positive(),
step: z.number().int().positive(),
step: z.number().int().nonnegative(),
provider: z.string().min(1),
model: z.string().min(1),
contextTokens: z.number().int().nonnegative().optional(),

View File

@@ -36,7 +36,7 @@ describe('ApiProxy model-request telemetry', () => {
} as Agent
ctx.agents.register(agent)
const measure = vi.fn(() => ({ totalTokens: 321 }))
const removeTokenMeter = ctx.provide('tokenMeter' as never, { measure } as never)
const removeTokenMeter = ctx.provide('tokenMeter', { measure })
const api = createApiProxy(ctx, {
provider: 'test',
model: 'alpha',

View File

@@ -365,7 +365,7 @@ describe('events frame schemas', () => {
type: 'session/model-request',
sessionId: 's',
turn: 2,
step: 1,
step: 0,
provider: 'deepseek',
model: 'deepseek-chat',
contextTokens: 8_000,
@@ -392,6 +392,7 @@ describe('events frame schemas', () => {
expect(() => muxFrameSchema.parse({ type: 'unknown/frame' })).toThrow()
for (const invalid of [
{ type: 'session/model-request', sessionId: 's', turn: 0, step: 1, provider: 'p', model: 'm' },
{ type: 'session/model-request', sessionId: 's', turn: 1, step: -1, provider: 'p', model: 'm' },
{ type: 'session/model-request', sessionId: 's', turn: 1, step: 1, provider: 'p', model: 'm', contextTokens: -1 },
{ type: 'session/model-request', sessionId: 's', turn: 1, step: 1, provider: 'p', model: 'm', contextWindow: 0 },
{ type: 'session/projection', sessionId: 's', key: '', value: null, seq: 0 },

View File

@@ -23,6 +23,9 @@
{
"path": "../../llm/llm"
},
{
"path": "../../llm/token-meter"
},
{
"path": "../../core/agent"
},