Files
deepseek-harness/packages/client/runtime/tests/context-provenance.spec.ts
creatixchu 340c9ba576 feat(web): split context injection into producer-declared forms
Injected context reached the transcript as one anonymous shape whose
expanded body was the whole message serialized as inline JSON, so the
escaping collapsed the only readable part — the model-facing prose —
into a single line.

`MessageSource` gains an optional producer-declared `form`, a small
semantic vocabulary of information shapes independent of `kind`: kind
says who produced the context, form says what shape it is, so several
producers may share one presentation. Two values ship.

`instructions` (workspace-context) lists the reconciled files above
their text and keeps the `<system-reminder>` framing verbatim, because
the framing is part of what the model read. `catalog` moves dsh-tool-skill
off the shared plugin kind onto a `skill-catalog` source carrying the
published name/description entries, and the body lists those instead of
re-parsing `<available_skills>` out of the prose. Catalog identity moves
with it: the republish digest now covers the durable entries, deleting
the text-slicing that recovered them from a logged message.

Everything else renders the opaque body — the model-facing text with its
real line breaks, then the remaining provenance as fields. That is the
documented default, not a leftover: a resumed, forked, or foreign log
must render whether or not its producer is mounted here, which is why
the classification lives in the durable source rather than a client-side
table keyed by producer.
2026-08-05 12:15:03 +08:00

85 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Context provenance projection: the role and producer name a transcript row
* shows for one logged non-user message, read from the durable source alone.
*/
import { describe, expect, it } from 'vitest'
import { contextForm, contextProvenance } from '../src/client/sessions/context-provenance.ts'
describe('contextProvenance', () => {
it('names a plugin producer by its logged plugin id', () => {
expect(contextProvenance({ kind: 'plugin', plugin: 'dsh-tool-skill' }))
.toEqual({ role: 'inject', label: 'dsh-tool-skill' })
})
it('names workspace instructions by the files they reconciled, deduplicated in first-seen order', () => {
expect(contextProvenance({
kind: 'workspace-instructions',
baseline: true,
changes: [
{ action: 'set', scope: '.AGENTS.md', path: 'AGENTS.md' },
{ action: 'set', scope: 'subAGENTS.md', path: 'sub/AGENTS.md' },
{ action: 'replace', scope: '.AGENTS.md', path: 'AGENTS.md' },
],
})).toEqual({ role: 'inject', label: 'AGENTS.md, sub/AGENTS.md' })
})
it('marks a cross-session snapshot as recall and names the sessions it read', () => {
expect(contextProvenance({
kind: 'session-reference',
version: 1,
references: [{ sessionId: 's1', label: 'Refactor the loader' }, { sessionId: 's2', label: 'Fix CI' }],
})).toEqual({ role: 'recall', label: 'Refactor the loader, Fix CI' })
})
it('identifies a producer this UI version does not know by its own durable kind', () => {
expect(contextProvenance({ kind: 'subagent-report', senderSessionId: 'child' }))
.toEqual({ role: 'inject', label: 'subagent-report' })
})
it('falls back to the source kind when the expected name field is unusable', () => {
// Every arm keeps the kind as its last readable name: a missing, empty, or
// wrongly-typed name field must not blank the row header.
expect(contextProvenance({ kind: 'plugin' }).label).toBe('plugin')
expect(contextProvenance({ kind: 'plugin', plugin: '' }).label).toBe('plugin')
expect(contextProvenance({ kind: 'plugin', plugin: 7 }).label).toBe('plugin')
expect(contextProvenance({ kind: 'workspace-instructions', changes: [] }).label)
.toBe('workspace-instructions')
expect(contextProvenance({ kind: 'workspace-instructions', changes: 'AGENTS.md' }).label)
.toBe('workspace-instructions')
expect(contextProvenance({ kind: 'workspace-instructions', changes: [{ action: 'set' }, null] }).label)
.toBe('workspace-instructions')
expect(contextProvenance({ kind: 'session-reference', references: [] }))
.toEqual({ role: 'recall', label: 'session-reference' })
})
it('degrades to an unnamed injection for a source that carries no readable kind', () => {
const unnamed = { role: 'inject', label: null }
expect(contextProvenance(null)).toEqual(unnamed)
expect(contextProvenance(undefined)).toEqual(unnamed)
expect(contextProvenance('plugin')).toEqual(unnamed)
expect(contextProvenance([{ kind: 'plugin' }])).toEqual(unnamed)
expect(contextProvenance({ plugin: 'dsh-tool-skill' })).toEqual(unnamed)
expect(contextProvenance({ kind: 42 })).toEqual(unnamed)
})
})
describe('contextForm', () => {
it('reads the form a producer declared', () => {
expect(contextForm({ kind: 'workspace-instructions', form: 'instructions', changes: [] }))
.toBe('instructions')
expect(contextForm({ kind: 'skill-catalog', form: 'catalog', entries: [] })).toBe('catalog')
})
it('degrades to the opaque presentation for anything this version does not present', () => {
// The durable vocabulary may already be wider than this UI version, and a
// source need not declare a form at all; neither may drop the row.
expect(contextForm({ kind: 'plugin', plugin: 'dsh-tool-skill' })).toBeNull()
expect(contextForm({ kind: 'plugin', form: 'snapshot' })).toBeNull()
expect(contextForm({ kind: 'plugin', form: '' })).toBeNull()
expect(contextForm({ kind: 'plugin', form: 7 })).toBeNull()
expect(contextForm(null)).toBeNull()
expect(contextForm('instructions')).toBeNull()
})
})