fix(scope): align trust and input boundaries

Rewrite the agent-scope RFC with executable examples and an explicit security non-goal. Harden subagent scalar and depth validation, and pin live tool-filter semantics across code, tests, and generated docs.
This commit is contained in:
Tianyi Cui
2026-07-12 11:17:57 +08:00
parent d427478c44
commit cb03c8c284
29 changed files with 545 additions and 105 deletions

View File

@@ -36,7 +36,7 @@ const SCHEMA: StructuredOutputSchema = {
}
/**
* Real loop + scripted mock model + an INLINE spawn-shaped provider over the
* Real loop + scripted mock model + an INLINE fresh-conversation provider over the
* shared driver. The concrete backend plugins are deliberately NOT loaded —
* they would devDep-cycle this package (spawn/fork already depend on the
* driver), and the runtime under test is the driver's; plugin-level structured

View File

@@ -48,6 +48,7 @@ describe('depthOf', () => {
})
it.each([
{ label: 'null', value: null as unknown as number },
{ label: 'a string', value: '1' as unknown as number },
{ label: 'NaN', value: Number.NaN },
{ label: 'positive infinity', value: Number.POSITIVE_INFINITY },
@@ -64,6 +65,7 @@ describe('depthOf', () => {
describe('startInProcessRun', () => {
it.each([
{ label: 'null', value: null as unknown as number },
{ label: 'a string', value: '1' as unknown as number },
{ label: 'NaN', value: Number.NaN },
{ label: 'positive infinity', value: Number.POSITIVE_INFINITY },
@@ -81,6 +83,27 @@ describe('startInProcessRun', () => {
}, {})).toThrow('subagent maxDepth must be a non-negative safe integer')
})
it('rejects a non-string persona before acquiring run ownership', async () => {
const { ctx, parent } = await setup([])
expect(() => startInProcessRun(ctx, {
prompt: [{ type: 'text', text: 'must never start' }],
parent,
persona: 42 as unknown as string,
}, {})).toThrow('subagent persona must be a string')
})
it('rejects a child depth with no safe-integer representation before acquiring run ownership', async () => {
const { ctx } = await setup([])
const parent = {
options: { subagentDepth: Number.MAX_SAFE_INTEGER },
} as unknown as Agent
expect(() => startInProcessRun(ctx, {
prompt: [{ type: 'text', text: 'must never start' }],
parent,
}, {})).toThrow(RangeError)
})
it('rejects a non-JSON prompt before acquiring any run ownership', async () => {
const { ctx, parent } = await setup([])
expect(() => startInProcessRun(ctx, {