Merge branch 'master' of https://github.com/deepseek-harness/deepseek-harness into xtr/react-loop-simplification
# Conflicts: # .agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.i18n.yaml # docs/architecture.i18n.yaml # docs/cookbook/extension-cookbook.i18n.yaml # docs/cordis-catalog/events.md # docs/cordis-catalog/services.md # docs/core-data-structures/core.i18n.yaml # docs/core-data-structures/core.md # docs/core-data-structures/core.zh.md # docs/core-data-structures/llm-streaming.i18n.yaml # docs/core-data-structures/llm-streaming.md # docs/core-data-structures/llm-streaming.zh.md # docs/core-data-structures/session.i18n.yaml # docs/event-producer-consumer.md # docs/persistence-catalog.md # packages/cordis/tool-cordis/src/api-catalog.ts # packages/core/agent-loop/README.i18n.yaml # packages/core/agent-loop/src/agent.ts # packages/core/agent/README.i18n.yaml # packages/core/session/README.i18n.yaml # packages/core/session/src/types.ts # packages/llm/llm/README.i18n.yaml # packages/llm/llm/README.md # packages/llm/llm/README.zh.md # packages/llm/llm/src/index.ts # packages/llm/llm/tests/service.spec.ts # packages/sdk/sdk-client/README.i18n.yaml # packages/sdk/sdk-protocol/README.i18n.yaml # packages/sdk/sdk-protocol/README.md # packages/sdk/sdk-protocol/README.zh.md # packages/subagent/subagent-dsh-sdk/README.i18n.yaml # packages/ui/jsonrpc/README.i18n.yaml # packages/ui/jsonrpc/README.md # packages/ui/jsonrpc/README.zh.md # packages/ui/tui/src/index.ts # python/sdk/README.i18n.yaml # scripts/gen-cordis-catalog.ts
This commit is contained in:
@@ -14,9 +14,24 @@ function tool(name: string, description = 'd'): ToolSchema {
|
||||
|
||||
describe('canonicalHeader', () => {
|
||||
it('normalizes empty optional fields to absence and preserves populated fields', () => {
|
||||
expect(canonicalHeader({ config: CONFIG, system: '', tools: [] })).toEqual({ config: CONFIG })
|
||||
const full = canonicalHeader({ config: CONFIG, system: 's', tools: [tool('a')] })
|
||||
expect(full).toEqual({ config: CONFIG, system: 's', tools: [tool('a')] })
|
||||
expect(canonicalHeader({
|
||||
config: CONFIG,
|
||||
adapterDefaults: {},
|
||||
system: '',
|
||||
tools: [],
|
||||
})).toEqual({ config: CONFIG })
|
||||
const full = canonicalHeader({
|
||||
config: { ...CONFIG, maxTokens: 256_000 },
|
||||
adapterDefaults: { maxTokens: true },
|
||||
system: 's',
|
||||
tools: [tool('a')],
|
||||
})
|
||||
expect(full).toEqual({
|
||||
config: { ...CONFIG, maxTokens: 256_000 },
|
||||
adapterDefaults: { maxTokens: true },
|
||||
system: 's',
|
||||
tools: [tool('a')],
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -30,6 +45,14 @@ describe('headerEquals', () => {
|
||||
...base,
|
||||
config: { ...base.config, reasoningEffort: ReasoningEffortId('high') },
|
||||
})).toBe(false)
|
||||
expect(headerEquals(
|
||||
{ ...base, config: { ...base.config, maxTokens: 256_000 } },
|
||||
{
|
||||
...base,
|
||||
config: { ...base.config, maxTokens: 256_000 },
|
||||
adapterDefaults: { maxTokens: true },
|
||||
},
|
||||
)).toBe(false)
|
||||
expect(headerEquals(base, { ...base, system: 'other' })).toBe(false)
|
||||
expect(headerEquals(base, { ...base, tools: [] })).toBe(false)
|
||||
expect(headerEquals(base, { ...base, tools: [tool('a', 'changed')] })).toBe(false)
|
||||
|
||||
@@ -351,6 +351,40 @@ describe('Session', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('round-trips adapter-default provenance and rejects invalid durable values', () => {
|
||||
const valid = {
|
||||
type: 'request/header',
|
||||
seq: 0,
|
||||
time: 1,
|
||||
data: {
|
||||
header: {
|
||||
config: {
|
||||
provider: 'mock',
|
||||
model: 'model',
|
||||
maxTokens: 256_000,
|
||||
},
|
||||
adapterDefaults: { maxTokens: true },
|
||||
},
|
||||
reason: 'initial',
|
||||
},
|
||||
} as const
|
||||
expect(new Session(SessionId('adapter-defaults'), [valid]).events[0]).toEqual(valid)
|
||||
|
||||
for (const adapterDefaults of [
|
||||
null,
|
||||
[],
|
||||
{ unknown: true },
|
||||
{ maxTokens: false },
|
||||
{ reasoningEffort: true },
|
||||
]) {
|
||||
const invalid = structuredClone(valid) as unknown as SessionEvent
|
||||
if (invalid.type !== 'request/header') throw new Error('test fixture must be a request header')
|
||||
invalid.data.header.adapterDefaults = adapterDefaults as never
|
||||
expect(() => new Session(SessionId('invalid-adapter-defaults'), [invalid]))
|
||||
.toThrow('seed request/header at index 0 has invalid adapterDefaults')
|
||||
}
|
||||
})
|
||||
|
||||
it('isolates the log from mutation through a derived message (append-only contract)', () => {
|
||||
const session = new Session(SessionId('s4'))
|
||||
session.append('user/message', createUserMessage({
|
||||
|
||||
@@ -4,6 +4,8 @@ import {
|
||||
Session,
|
||||
SessionId,
|
||||
foldSurface,
|
||||
isAppendSurfaceEvent,
|
||||
isReplacementSurfaceEvent,
|
||||
isSurfaceEligibleType,
|
||||
isSurfaceEvent,
|
||||
} from '@deepseek-ai/dsh-session'
|
||||
@@ -861,6 +863,40 @@ describe('surface type guards', () => {
|
||||
expect(isSurfaceEligibleType(markerless.type)).toBe(true)
|
||||
expect(isSurfaceEvent(markerless)).toBe(false)
|
||||
})
|
||||
|
||||
it('splits surface events into append-origin and replacement by their marker', () => {
|
||||
const s = surfaceSession()
|
||||
s.append('user/message', createUserMessage({
|
||||
content: [{ type: 'text', text: 'checkpoint' }], source: { kind: 'plugin', plugin: 'compact' },
|
||||
}), { surfaceOp: { op: 'replace', start: 1, end: 2 }, sourceEventSeqs: [1, 2] })
|
||||
const appended = s.events.find(e => e.type === 'user/message')!
|
||||
const replacement = s.events.at(-1)!
|
||||
|
||||
expect(isAppendSurfaceEvent(appended)).toBe(true)
|
||||
expect(isReplacementSurfaceEvent(appended)).toBe(false)
|
||||
expect(isAppendSurfaceEvent(replacement)).toBe(false)
|
||||
expect(isReplacementSurfaceEvent(replacement)).toBe(true)
|
||||
})
|
||||
|
||||
it('rejects log-only and markerless events from both marker guards', () => {
|
||||
const s = surfaceSession()
|
||||
const turnStart = s.events.find(e => e.type === 'turn/start')!
|
||||
// A surface-eligible type whose mandatory marker is absent has no origin at
|
||||
// all: it never entered the surface.
|
||||
const markerless: SessionEvent = {
|
||||
type: 'user/message',
|
||||
seq: 0,
|
||||
time: 0,
|
||||
data: createUserMessage({
|
||||
content: [{ type: 'text', text: 'hi' }], source: { kind: 'user' },
|
||||
}),
|
||||
}
|
||||
|
||||
expect(isAppendSurfaceEvent(turnStart)).toBe(false)
|
||||
expect(isReplacementSurfaceEvent(turnStart)).toBe(false)
|
||||
expect(isAppendSurfaceEvent(markerless)).toBe(false)
|
||||
expect(isReplacementSurfaceEvent(markerless)).toBe(false)
|
||||
})
|
||||
})
|
||||
|
||||
describe('SurfaceManager.replaceGeneration', () => {
|
||||
|
||||
Reference in New Issue
Block a user