Merge remote-tracking branch 'origin/worktree-agent-scope-design' into codex/trim-ai-prose

This commit is contained in:
Tianyi Cui
2026-07-13 12:07:23 +08:00
33 changed files with 148 additions and 126 deletions

View File

@@ -171,7 +171,7 @@ describe('mode-aware wire contribution', () => {
expect(result.isError).toBe(false)
expect(result.content).toEqual([{ type: 'text', text: 'echo' }])
await lift()
lift()
const unrestricted = await systemPrompt.assemble({ scope: agent })
expect(unrestricted.tools.map(tool => tool.name)).toEqual(mode === 'code'
? [RUN_CODE_NAME]

View File

@@ -1,5 +1,6 @@
import { describe, expect, it, vi } from 'vitest'
import { describe, expect, expectTypeOf, it, vi } from 'vitest'
import { Context } from 'cordis'
import type { Events } from 'cordis'
import { createScope } from '@deepseek-ai/dsh-scope'
import type { Scope } from '@deepseek-ai/dsh-scope'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
@@ -50,6 +51,14 @@ async function run(ctx: Context, name: string, agent?: Agent): Promise<string> {
}
describe('scoped tool registration', () => {
it('keeps final-result observers synchronous', () => {
type ToolResultListener = Events['tools/result']
type AsyncToolResultListener = () => Promise<void>
expectTypeOf<AsyncToolResultListener>().not.toExtend<ToolResultListener>()
expectTypeOf<ReturnType<ToolResultListener>>().toEqualTypeOf<undefined>()
})
it('files a scoped tool in its layer: visible/executable for that scope only', async () => {
const ctx = await mount()
const { scope, key } = await mintAgentScope(ctx, 'a')
@@ -177,7 +186,7 @@ describe('restrict()', () => {
const liftAllow = scope.ctx.tools.restrict({ allow: ['a', 'b'] })
scope.ctx.tools.restrict({ deny: ['b'] })
expect(ctx.tools.schemas(key).map(t => t.name)).toEqual(['a'])
await liftAllow()
liftAllow()
// The deny remains after the allow-list is lifted.
expect(ctx.tools.schemas(key).map(t => t.name).sort()).toEqual(['a', 'c'])
})
@@ -257,7 +266,7 @@ describe('scoped execution dispatch', () => {
expect(await run(ctx, 't', other)).toBe('ran:t')
expect(bodyCalls).toBe(1)
await liftFirst()
liftFirst()
expect(await run(ctx, 't', key)).toBe('Error: terminal policy')
await scope.dispose()
expect(await run(ctx, 't', key)).toBe('ran:t')
@@ -607,7 +616,7 @@ describe('scoped execution dispatch', () => {
const result = await ctx.tools.execute({ callId: CallId('final'), name: 't', arguments: {}, agent: key })
expect(result).toMatchObject({ isError: true, content: [{ type: 'text', text: 'outer failure' }] })
expect(seen).toEqual([true, true])
expect(dispatchModes).toEqual(['parallel'])
expect(dispatchModes).toEqual(['emit'])
expect(warn).toHaveBeenCalledOnce()
expect(String(warn.mock.calls[0]?.[0])).toContain('<unprintable thrown value>')
})

View File

@@ -677,7 +677,7 @@ describe('ToolRegistry', () => {
const dispose = ctx.tools.register({ ...echoTool, name: 'disposable' })
expect(ctx.tools.schemas().map(t => t.name)).toEqual(['echo', 'disposable'])
await dispose()
dispose()
expect(ctx.tools.schemas().map(t => t.name)).toEqual(['echo'])
})
@@ -698,7 +698,7 @@ describe('ToolRegistry', () => {
// exposed exactly once (the duplicate-name check is not wedged).
const dispose = ctx.tools.register(echoTool)
expect(ctx.tools.schemas().map(t => t.name)).toEqual(['echo'])
await dispose()
dispose()
expect(ctx.tools.get('echo')).toBeUndefined()
})