fix(invariants): assert runtime relationships, not API shapes

This commit is contained in:
Tianyi Cui
2026-07-20 19:34:19 +08:00
parent 1254c07025
commit 1145ee5fc3
124 changed files with 2923 additions and 2334 deletions

View File

@@ -1,27 +1,24 @@
/** Package-owned runtime contract checks for `@deepseek-ai/dsh-llm-deepseek`. @module @deepseek-ai/dsh-llm-deepseek/invariant */
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-llm-deepseek`.
* @module @deepseek-ai/dsh-llm-deepseek/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import { observePluginInvariant, type InvariantInstaller } from '@deepseek-ai/dsh-invariants'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-llm-deepseek'
/** Cordis companion plugin name. */
export const name = 'llm-deepseek-invariant'
/** Services required before the companion can register. */
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/** Install checks for this package's active plugin fibers. */
const install: InvariantInstaller = (ctx, fail) => {
observePluginInvariant(ctx, fail, {
name: 'llm-deepseek',
inject: [
'llm',
],
effects: [
'llm.registerAdapter()',
],
})
}
/**
* No runtime invariant: this package exposes no independent event sequence or mutable data relation
* beyond contracts enforced at its owning seam.
*/
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
@@ -30,3 +27,4 @@ const install: InvariantInstaller = (ctx, fail) => {
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -1,27 +1,24 @@
/** Package-owned runtime contract checks for `@deepseek-ai/dsh-llm-pi-ai`. @module @deepseek-ai/dsh-llm-pi-ai/invariant */
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-llm-pi-ai`.
* @module @deepseek-ai/dsh-llm-pi-ai/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import { observePluginInvariant, type InvariantInstaller } from '@deepseek-ai/dsh-invariants'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-llm-pi-ai'
/** Cordis companion plugin name. */
export const name = 'llm-pi-ai-invariant'
/** Services required before the companion can register. */
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/** Install checks for this package's active plugin fibers. */
const install: InvariantInstaller = (ctx, fail) => {
observePluginInvariant(ctx, fail, {
name: 'llm-pi-ai',
inject: [
'llm',
],
effects: [
'llm.registerAdapter()',
],
})
}
/**
* No runtime invariant: this package exposes no independent event sequence or mutable data relation
* beyond contracts enforced at its owning seam.
*/
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
@@ -30,3 +27,4 @@ const install: InvariantInstaller = (ctx, fail) => {
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */

View File

@@ -1,30 +1,93 @@
/** Package-owned runtime contract checks for `@deepseek-ai/dsh-llm`. @module @deepseek-ai/dsh-llm/invariant */
/** Package-owned LLM stream-protocol invariants. @module @deepseek-ai/dsh-llm/invariant */
import type { Context } from 'cordis'
import { observePluginInvariant, type InvariantInstaller } from '@deepseek-ai/dsh-invariants'
import type { InvariantFailure, InvariantInstaller } from '@deepseek-ai/dsh-invariants'
import type { ContentBlockType, StreamChunk } from './types.ts'
const PACKAGE_NAME = '@deepseek-ai/dsh-llm'
/** Cordis companion plugin name. */
export const name = 'llm-invariant'
/** Services required before the companion can register. */
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/** Install checks for this package's active plugin fibers. */
/** Require one chunk index to be a non-negative safe integer. */
function validateIndex(index: number, fail: InvariantFailure): void {
if (!Number.isSafeInteger(index) || index < 0) {
fail(`LLM stream block index must be a non-negative safe integer, got ${index}`)
}
}
/** Require a delta to address an open block of its matching type. */
function validateDelta(
open: ReadonlyMap<number, ContentBlockType>,
index: number,
expected: ContentBlockType,
fail: InvariantFailure,
): void {
validateIndex(index, fail)
const actual = open.get(index)
if (actual !== expected) {
fail(`${expected} delta at index ${index} requires an open ${expected} block, got ${String(actual)}`)
}
}
/** Wrap one provider stream and enforce its grammar as chunks are consumed. */
async function* validateStream(
source: AsyncIterable<StreamChunk>,
fail: InvariantFailure,
): AsyncIterable<StreamChunk> {
const open = new Map<number, ContentBlockType>()
let usageSeen = false
let finished = false
for await (const chunk of source) {
if (finished) fail(`LLM stream emitted ${chunk.type} after terminal finish`)
switch (chunk.type) {
case 'block-start':
validateIndex(chunk.index, fail)
if (open.has(chunk.index)) fail(`LLM stream repeated block-start index ${chunk.index}`)
open.set(chunk.index, chunk.blockType)
break
case 'text-delta':
validateDelta(open, chunk.index, 'text', fail)
break
case 'reasoning-delta':
validateDelta(open, chunk.index, 'reasoning', fail)
break
case 'tool-call-delta':
validateDelta(open, chunk.index, 'tool-call', fail)
break
case 'block-end': {
validateIndex(chunk.index, fail)
const blockType = open.get(chunk.index)
if (blockType === undefined) fail(`LLM stream block-end index ${chunk.index} has no open block`)
if (chunk.block.type !== blockType) {
fail(`LLM stream block-end index ${chunk.index} closes ${chunk.block.type}, expected ${blockType}`)
}
open.delete(chunk.index)
break
}
case 'usage':
if (usageSeen) fail('LLM stream emitted usage more than once')
usageSeen = true
break
case 'finish':
if (open.size > 0) fail(`LLM stream finished with ${open.size} open block(s)`)
finished = true
break
}
yield chunk
}
if (!finished) fail('LLM stream ended without a terminal finish chunk')
}
/** Install validation around every provider stream. */
const install: InvariantInstaller = (ctx, fail) => {
observePluginInvariant(ctx, fail, {
name: 'LlmService',
effects: [
'ctx.provide("llm")',
],
services: [
'llm',
],
})
ctx.on('llm/stream', (_options, next) => validateStream(next(), fail), { global: true, prepend: true })
}
/**
* Register this package's invariant companion.
* Register the LLM invariant companion.
* @param ctx - Cordis context carrying the invariant service.
* @returns the installed registration's disposer after setup succeeds.
*/

View File

@@ -0,0 +1,86 @@
import { describe, expect, it } from 'vitest'
import { Context } from 'cordis'
import { CallId } from '@deepseek-ai/dsh-llm'
import type { GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm'
import * as LlmInvariant from '@deepseek-ai/dsh-llm/invariant'
import InvariantService from '@deepseek-ai/dsh-invariants'
async function setup(): Promise<Context> {
const ctx = new Context()
await ctx.plugin(InvariantService)
await ctx.plugin(LlmInvariant)
return ctx
}
const options: GenerateOptions = { provider: 'mock', model: 'mock', messages: [] }
async function* source(chunks: readonly StreamChunk[]): AsyncIterable<StreamChunk> {
yield* chunks
}
async function consume(ctx: Context, chunks: readonly StreamChunk[]): Promise<StreamChunk[]> {
const stream = ctx.waterfall(ctx as never, 'llm/stream', options, () => source(chunks))
const consumed: StreamChunk[] = []
for await (const chunk of stream) consumed.push(chunk)
return consumed
}
const finish: StreamChunk = { type: 'finish', reason: { kind: 'stop' } }
describe('LLM stream invariants', () => {
it('accepts a complete interleaved stream grammar', async () => {
const ctx = await setup()
const chunks: StreamChunk[] = [
{ type: 'block-start', index: 0, blockType: 'text' },
{ type: 'text-delta', index: 0, text: 'a' },
{ type: 'block-start', index: 1, blockType: 'reasoning' },
{ type: 'reasoning-delta', index: 1, text: 'b' },
{ type: 'block-end', index: 1, block: { type: 'reasoning', text: 'b' } },
{ type: 'block-end', index: 0, block: { type: 'text', text: 'a' } },
{ type: 'block-start', index: 2, blockType: 'tool-call' },
{ type: 'tool-call-delta', index: 2, id: CallId('c1'), name: 'echo', argumentsDelta: '{}' },
{ type: 'block-end', index: 2, block: { type: 'tool-call', id: CallId('c1'), name: 'echo', arguments: '{}' } },
{ type: 'usage', usage: { inputTokens: 1, outputTokens: 1 } },
finish,
]
await expect(consume(ctx, chunks)).resolves.toEqual(chunks)
})
it.each([
[[{ type: 'block-start', index: -1, blockType: 'text' }, finish], /non-negative safe integer/],
[[
{ type: 'block-start', index: 0, blockType: 'text' },
{ type: 'block-start', index: 0, blockType: 'text' },
], /repeated block-start/],
[[{ type: 'text-delta', index: 0, text: 'x' }], /requires an open text block/],
[[
{ type: 'block-start', index: 0, blockType: 'reasoning' },
{ type: 'text-delta', index: 0, text: 'x' },
], /got reasoning/],
[[{ type: 'block-end', index: 0, block: { type: 'text', text: '' } }], /has no open block/],
[[
{ type: 'block-start', index: 0, blockType: 'text' },
{ type: 'block-end', index: 0, block: { type: 'reasoning', text: '' } },
], /closes reasoning, expected text/],
[[
{ type: 'usage', usage: { inputTokens: 1, outputTokens: 1 } },
{ type: 'usage', usage: { inputTokens: 1, outputTokens: 1 } },
], /usage more than once/],
[[{ type: 'block-start', index: 0, blockType: 'text' }, finish], /finished with 1 open block/],
[[finish, { type: 'usage', usage: { inputTokens: 1, outputTokens: 1 } }], /usage after terminal finish/],
[[], /ended without a terminal finish/],
] as Array<[StreamChunk[], RegExp]>)('rejects malformed stream %#', async (chunks, message) => {
const ctx = await setup()
await expect(consume(ctx, chunks)).rejects.toThrow(message)
})
it('preserves provider exceptions without inventing a missing-finish failure', async () => {
const ctx = await setup()
const stream = ctx.waterfall(ctx as never, 'llm/stream', options, async function* () {
throw new Error('provider failed')
})
await expect((async () => {
for await (const _chunk of stream) { /* consume */ }
})()).rejects.toThrow('provider failed')
})
})

View File

@@ -60,6 +60,7 @@ class CatalogAdapter extends ScriptedAdapter {
const SCRIPT: StreamChunk[] = [
{ type: 'block-start', index: 0, blockType: 'text' },
{ type: 'text-delta', index: 0, text: 'hi' },
{ type: 'block-end', index: 0, block: { type: 'text', text: 'hi' } },
{ type: 'finish', reason: { kind: 'stop' } },
]
@@ -489,13 +490,14 @@ describe('LlmService', () => {
const inner = next()
return (async function * () {
yield { type: 'block-start', index: 99, blockType: 'text' } satisfies StreamChunk
yield { type: 'block-end', index: 99, block: { type: 'text', text: '' } } satisfies StreamChunk
yield * inner
})()
})
const chunks: StreamChunk[] = []
for await (const chunk of ctx.llm.stream({ provider: 'test-model', model: 'dynamic-model', messages: [] })) chunks.push(chunk)
expect(chunks).toHaveLength(4)
expect(chunks).toHaveLength(6)
expect(chunks[0]).toMatchObject({ index: 99 })
})

View File

@@ -1,28 +1,24 @@
/** Package-owned runtime contract checks for `@deepseek-ai/dsh-token-meter`. @module @deepseek-ai/dsh-token-meter/invariant */
/**
* Package-owned invariant companion for `@deepseek-ai/dsh-token-meter`.
* @module @deepseek-ai/dsh-token-meter/invariant
*/
/* jscpd:ignore-start */
import type { Context } from 'cordis'
import { observePluginInvariant, type InvariantInstaller } from '@deepseek-ai/dsh-invariants'
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
const PACKAGE_NAME = '@deepseek-ai/dsh-token-meter'
/** Cordis companion plugin name. */
export const name = 'token-meter-invariant'
/** Services required before the companion can register. */
/** Service required before the companion can reserve package ownership. */
export const inject = ['invariants']
/** Install checks for this package's active plugin fibers. */
const install: InvariantInstaller = (ctx, fail) => {
observePluginInvariant(ctx, fail, {
name: 'TokenMeterService',
effects: [
'ctx.provide("tokenMeter")',
'ctx.on("session/event")',
],
services: [
'tokenMeter',
],
})
}
/**
* No runtime invariant: token estimates are per-call outputs and the private session cache is
* invalidated at its event mutation boundary; neither exposes an independent observation stream.
*/
const install: InvariantInstaller = () => {}
/**
* Register this package's invariant companion.
@@ -31,3 +27,4 @@ const install: InvariantInstaller = (ctx, fail) => {
*/
export const apply = (ctx: Context): Promise<() => void> =>
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
/* jscpd:ignore-end */