Merge remote-tracking branch 'origin/master' into feat/read-image-context

# Conflicts:
#	apps/cli/tests/web-agent-presets.e2e.ts
#	packages/fs/tool-fs/package.json
This commit is contained in:
creatixchu
2026-08-11 10:12:14 +08:00
1962 changed files with 25048 additions and 14905 deletions

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { Context } from 'cordis'
import { Context } from '@deepseek-ai/cordis'
import { createUserMessage, CallId } from '@deepseek-ai/dsh-llm'
import { createScope } from '@deepseek-ai/dsh-scope'
import type { Scope } from '@deepseek-ai/dsh-scope'

View File

@@ -1,7 +1,7 @@
/** Covers fail-closed per-call classification and model-schema isolation. */
import { describe, expect, expectTypeOf, it } from 'vitest'
import { Context } from 'cordis'
import { Context } from '@deepseek-ai/cordis'
import { CallId } from '@deepseek-ai/dsh-llm'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import ToolRegistry, {

View File

@@ -1,5 +1,5 @@
import { describe, expectTypeOf, it } from 'vitest'
import type { Context } from 'cordis'
import type { Context } from '@deepseek-ai/cordis'
import { CallId } from '@deepseek-ai/dsh-llm'
import { defineTool } from '@deepseek-ai/dsh-tools'
import type {

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from 'vitest'
import { Context } from 'cordis'
import { Context } from '@deepseek-ai/cordis'
import { scopeTarget } from '@deepseek-ai/dsh-scope'
import { CallId } from '@deepseek-ai/dsh-llm'
import SessionStore, { Session, SessionId } from '@deepseek-ai/dsh-session'

View File

@@ -1,7 +1,7 @@
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 { Context } from '@deepseek-ai/cordis'
import type { Events } from '@deepseek-ai/cordis'
import { bindScopeParent, createScope } from '@deepseek-ai/dsh-scope'
import type { Scope } from '@deepseek-ai/dsh-scope'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import ToolRegistry from '@deepseek-ai/dsh-tools'
@@ -181,21 +181,84 @@ describe('restrict()', () => {
expect(ctx.tools.schemas(key).map(t => t.name)).toEqual(['b'])
})
it('fails loud on an unscoped call, an empty filter, and non-global names', async () => {
it('fails loud on an unscoped call, an empty filter, and names it does not inherit', async () => {
const ctx = await mount()
const { scope } = await mintAgentScope(ctx, 'a')
ctx.tools.register(tool('real'))
scope.ctx.tools.register(tool('local'))
expect(() => ctx.tools.restrict({ deny: ['real'] })).toThrow(/requires a scoped context/)
expect(() => scope.ctx.tools.restrict({})).toThrow(/no-op/)
expect(() => scope.ctx.tools.restrict({ allow: ['local'] })).toThrow(/unknown global tool "local"/)
expect(() => scope.ctx.tools.restrict({ allow: ['reall'] })).toThrow(/unknown global tool "reall"; known global tools: real/)
expect(() => scope.ctx.tools.restrict({ deny: ['ghost', 'wraith'] })).toThrow(/unknown global tools "ghost", "wraith"/)
// A scope's own registration is exempt from its own filter, so naming it
// is a caller error rather than a silent no-op.
expect(() => scope.ctx.tools.restrict({ allow: ['local'] })).toThrow(/unknown inherited tool "local"/)
expect(() => scope.ctx.tools.restrict({ allow: ['reall'] })).toThrow(/unknown inherited tool "reall".*Restrictable tools: real/s)
expect(() => scope.ctx.tools.restrict({ deny: ['ghost', 'wraith'] })).toThrow(/unknown inherited tools "ghost", "wraith"/)
const emptyCtx = await mount()
const { scope: emptyScope } = await mintAgentScope(emptyCtx, 'empty')
expect(() => emptyScope.ctx.tools.restrict({ deny: ['ghost'] }))
.toThrow(/known global tools: \(none\)/)
.toThrow(/Restrictable tools: \(none\)/)
})
})
describe('restrict() over an inherited scope layer', () => {
/** Mint a child scope parented to `parent`, as a subagent's creation window does. */
async function mintChild(ctx: Context, parentKey: Agent, name: string): Promise<{ scope: Scope; key: Agent }> {
const key = { id: name as SessionId } as Agent
bindScopeParent(key, parentKey)
let scope!: Scope
await ctx.plugin(Object.assign((inner: Context) => { scope = createScope(inner, key) },
{ inject: ['tools', 'systemPrompt'] }))
return { scope, key }
}
it('filters tools the child inherits from an ancestor scope, not only global ones', async () => {
// The shape every preset deployment has: no model-facing row in the global
// layer, all of them contributed by an ancestor scope the child joined.
const ctx = await mount()
const parent = await mintAgentScope(ctx, 'parent')
parent.scope.ctx.tools.register(tool('bash'))
parent.scope.ctx.tools.register(tool('read'))
const child = await mintChild(ctx, parent.key, 'child')
expect(ctx.tools.schemas(child.key).map(t => t.name).sort()).toEqual(['bash', 'read'])
child.scope.ctx.tools.restrict({ deny: ['bash'] })
// Reading the exempt set as "the global layer" left this unfiltered, and
// the name unrestrictable in the first place.
expect(ctx.tools.schemas(child.key).map(t => t.name)).toEqual(['read'])
expect(await run(ctx, 'bash', child.key)).toBe('Error: unknown tool "bash"')
// The ancestor keeps its whole surface: a child's filter is its own.
expect(ctx.tools.schemas(parent.key).map(t => t.name).sort()).toEqual(['bash', 'read'])
})
it('keeps the child\'s own registrations outside its own filter', async () => {
// The delegation runtime registers a child's reporting and structured
// output tools into the child's own layer; an `allow` naming only the
// capabilities the child may use must not strip them.
const ctx = await mount()
const parent = await mintAgentScope(ctx, 'parent')
parent.scope.ctx.tools.register(tool('bash'))
parent.scope.ctx.tools.register(tool('read'))
const child = await mintChild(ctx, parent.key, 'child')
child.scope.ctx.tools.register(tool('report'))
child.scope.ctx.tools.restrict({ allow: ['read'] })
expect(ctx.tools.schemas(child.key).map(t => t.name).sort()).toEqual(['read', 'report'])
expect(await run(ctx, 'report', child.key)).toBe('ran:report')
})
it('lets an ancestor\'s restriction reach every scope nested inside it', async () => {
const ctx = await mount()
ctx.tools.register(tool('web'))
const parent = await mintAgentScope(ctx, 'parent')
parent.scope.ctx.tools.register(tool('bash'))
const child = await mintChild(ctx, parent.key, 'child')
parent.scope.ctx.tools.restrict({ deny: ['web'] })
expect(ctx.tools.schemas(child.key).map(t => t.name)).toEqual(['bash'])
expect(ctx.tools.schemas(parent.key).map(t => t.name)).toEqual(['bash'])
})
})

View File

@@ -1,5 +1,5 @@
import { describe, expect, expectTypeOf, it } from 'vitest'
import { Context } from 'cordis'
import { Context } from '@deepseek-ai/cordis'
import { createUserMessage, CallId, HarnessError, type ContentBlock } from '@deepseek-ai/dsh-llm'
import SystemPrompt from '@deepseek-ai/dsh-system-prompt'
import type { Agent } from '@deepseek-ai/dsh-agent'