refactor(scope): migrate tool and prompt layers

This commit is contained in:
Tianyi Cui
2026-07-21 22:14:49 +08:00
parent 8351cdbe65
commit 1d209932d6
5 changed files with 195 additions and 203 deletions

View File

@@ -1,4 +1,4 @@
import { describe, expect, it } from 'vitest'
import { describe, expect, it, vi } from 'vitest'
import { Context } from 'cordis'
import { createScope, scopeOf } from '@deepseek-ai/dsh-scope'
import type { Scope, ScopeKey } from '@deepseek-ai/dsh-scope'
@@ -63,6 +63,21 @@ describe('scoped sections', () => {
expect(() => scope.ctx.systemPrompt.section({ name: 'y', order: 1, text: 'b' })).toThrow(/already registered in this scope/)
})
it('shadows a global section before evaluating either text provider', async () => {
const ctx = await mount()
const scope = await mintScope(ctx, 'child')
const globalText = vi.fn(() => 'global text')
const scopedText = vi.fn(() => 'scoped text')
ctx.systemPrompt.section({ name: 'shared', order: 1, text: globalText })
scope.ctx.systemPrompt.section({ name: 'shared', order: 1, text: scopedText })
const assembly = await ctx.systemPrompt.assemble({ scope: scopeKeyOf(scope) })
expect(assembly.sections.find(section => section.name === 'shared')?.text).toBe('scoped text')
expect(globalText).not.toHaveBeenCalled()
expect(scopedText).toHaveBeenCalledOnce()
})
})
describe('scoped variables', () => {

View File

@@ -157,6 +157,24 @@ describe('SystemPrompt', () => {
expect((await ctx.systemPrompt.assemble()).tools.map(t => t.name)).toEqual(['t'])
})
it('snapshots tool-provider membership before evaluating an assembly', async () => {
const ctx = new Context()
await ctx.plugin(SystemPrompt)
let added = false
ctx.systemPrompt.tools(() => {
if (!added) {
added = true
ctx.systemPrompt.tools(() => ({
schemas: [{ name: 'late', description: '', parameters: {} }],
}))
}
return { schemas: [{ name: 'first', description: '', parameters: {} }] }
})
expect((await ctx.systemPrompt.assemble()).tools.map(tool => tool.name)).toEqual(['first'])
expect((await ctx.systemPrompt.assemble()).tools.map(tool => tool.name)).toEqual(['first', 'late'])
})
it('rolls back a variable when a system-prompt/change listener throws (P1-1)', async () => {
const ctx = new Context()
await ctx.plugin(SystemPrompt)
@@ -314,6 +332,24 @@ describe('SystemPrompt', () => {
expect((await ctx.systemPrompt.assemble()).variables).toEqual({})
})
it('live-iterates variables registered by an earlier provider', async () => {
const ctx = new Context()
await ctx.plugin(SystemPrompt)
let added = false
ctx.systemPrompt.variable('first', () => {
if (!added) {
added = true
ctx.systemPrompt.variable('late', () => 'second value')
}
return 'first value'
})
expect((await ctx.systemPrompt.assemble()).variables).toEqual({
first: 'first value',
late: 'second value',
})
})
it('rejects a duplicate variable name and an unreferenceable name', async () => {
const ctx = new Context()
await ctx.plugin(SystemPrompt)