review: symmetric policy-service type imports, drop stale inprocess peers, pin child-switch and fork-default cases
- child-agent.ts declares both policy-service augmentations as explicit
empty type imports, so removing the ApprovalPolicy import cannot
silently degrade ctx.get('approval') typing.
- dsh-subagent-inprocess no longer consumes the policy services in src,
so its optional peers and tsconfig references are dropped; both
policy-inheritance Agent Notes state the current ownership.
- The continuable suite pins that a later child-side switch beats the
delegation snapshot and that an unswitched fork parent seeds no
policy events.
This commit is contained in:
@@ -28,22 +28,12 @@
|
||||
"@deepseek-ai/dsh-agent": "^0.0.1",
|
||||
"@deepseek-ai/dsh-invariants": "^0.0.1",
|
||||
"@deepseek-ai/dsh-llm": "^0.0.1",
|
||||
"@deepseek-ai/dsh-sandbox-policy": "^0.0.1",
|
||||
"@deepseek-ai/dsh-session": "^0.0.1",
|
||||
"@deepseek-ai/dsh-subagent": "^0.0.1",
|
||||
"@deepseek-ai/dsh-system-prompt": "^0.0.1",
|
||||
"@deepseek-ai/dsh-tools": "^0.0.1",
|
||||
"@deepseek-ai/dsh-user-approval": "^0.0.1",
|
||||
"cordis": "^4.0.0-rc.7"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@deepseek-ai/dsh-sandbox-policy": {
|
||||
"optional": true
|
||||
},
|
||||
"@deepseek-ai/dsh-user-approval": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-agent": "workspace:^",
|
||||
"@deepseek-ai/dsh-agent-loop": "workspace:^",
|
||||
|
||||
@@ -32,14 +32,8 @@
|
||||
{
|
||||
"path": "../../core/tools"
|
||||
},
|
||||
{
|
||||
"path": "../../sandbox/sandbox-policy"
|
||||
},
|
||||
{
|
||||
"path": "../../support/invariants"
|
||||
},
|
||||
{
|
||||
"path": "../../interaction/user-approval"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -17,7 +17,10 @@ import type { ApprovalPolicy } from '@deepseek-ai/dsh-user-approval'
|
||||
// Type-only: make `ctx.get('sandboxPolicy')` / `ctx.get('approval')` resolve
|
||||
// to the policy services when composed — delegation consumes both
|
||||
// opportunistically (the documented `ctx.get` pattern), never as a hard dep.
|
||||
// The user-approval side stays an explicit empty import so its augmentation
|
||||
// does not ride the `ApprovalPolicy` import above.
|
||||
import type {} from '@deepseek-ai/dsh-sandbox-policy'
|
||||
import type {} from '@deepseek-ai/dsh-user-approval'
|
||||
import { delegationDepthOf } from './depth.ts'
|
||||
|
||||
/** Thrown when starting a child would exceed the requested depth cap. */
|
||||
|
||||
@@ -124,6 +124,42 @@ describe('continuable policy inheritance', () => {
|
||||
expect(policyEvents(loaded.events)).toEqual([])
|
||||
})
|
||||
|
||||
it('does not freeze deployment defaults into an unswitched fork child either', async () => {
|
||||
const { ctx, parent } = await setup([textResponse('parent turn'), textResponse('forked child')])
|
||||
parent.followup(createUserMessage({
|
||||
content: [{ type: 'text', text: 'parent work' }],
|
||||
source: { kind: 'user' },
|
||||
}))
|
||||
await parent.whenIdle()
|
||||
|
||||
const started = await ctx.subagents.startContinuable(startSpec(parent, 'fork'))
|
||||
await waitNoActivation(ctx, started.childId)
|
||||
|
||||
const loaded = await ctx.sessionPersistence.load(started.childId)
|
||||
expect(loaded.meta.seedLength).toBeGreaterThan(0)
|
||||
expect(policyEvents(loaded.events)).toEqual([])
|
||||
})
|
||||
|
||||
it('lets a later child-side switch win over the delegation snapshot', async () => {
|
||||
const { ctx, parent } = await setup([textResponse('child done')])
|
||||
setSandboxMode(parent.session, 'danger-full-access')
|
||||
let child: Agent | undefined
|
||||
ctx.on('agent/created', ({ agent }) => {
|
||||
if (agent !== parent) child = agent
|
||||
})
|
||||
|
||||
const started = await ctx.subagents.startContinuable(startSpec(parent))
|
||||
if (child === undefined) throw new Error('expected the continuable child to be created')
|
||||
expect(ctx.sandboxPolicy.overrideOf(child.session)).toBe('danger-full-access')
|
||||
// Last event wins: the child's own runtime switch beats the seeded snapshot.
|
||||
setSandboxMode(child.session, 'read-only')
|
||||
expect(ctx.sandboxPolicy.overrideOf(child.session)).toBe('read-only')
|
||||
|
||||
await waitNoActivation(ctx, started.childId)
|
||||
const loaded = await ctx.sessionPersistence.load(started.childId)
|
||||
expect(effectiveSandboxMode(loaded.events)).toBe('read-only')
|
||||
})
|
||||
|
||||
it('cold-resumes on the persisted snapshot without re-capturing the parent', async () => {
|
||||
const { ctx, parent } = await setup([textResponse('first'), textResponse('after resume')])
|
||||
setSandboxMode(parent.session, 'read-only')
|
||||
|
||||
Reference in New Issue
Block a user