Merge latest origin/master into parallel-tool-call

This commit is contained in:
Tianyi Cui
2026-07-17 22:28:38 +08:00
313 changed files with 4454 additions and 1922 deletions

View File

@@ -30,7 +30,7 @@ async function setup(script: Script) {
await ctx.plugin(Spawn, { providerName: 'spawn' })
await ctx.plugin(fork, { providerName: 'fork' })
ctx.llm.registerAdapter(['mock'], new MockAdapter(script))
const parent = ctx.agentLoop.create(AgentId('parent'), { model: 'mock' })
const parent = ctx.agentLoop.create(AgentId('parent'), { provider: 'mock', model: 'mock' })
return { ctx, parent }
}

View File

@@ -36,7 +36,7 @@ async function setup(script: Script) {
await ctx.plugin(SubagentService)
await ctx.plugin(fork, { providerName: 'fork' })
ctx.llm.registerAdapter(['mock'], new MockAdapter(script))
const parent = ctx.agentLoop.create(AgentId('parent'), { model: 'mock' })
const parent = ctx.agentLoop.create(AgentId('parent'), { provider: 'mock', model: 'mock' })
return { ctx, parent }
}

View File

@@ -107,8 +107,10 @@ export async function startInProcessRun(
const childId = AgentId(randomUUID())
const seedLength = options.seed?.length ?? 0
const parentHeader = parent.session.header
const parentProvider = parent.options.provider
const parentModel = parent.options.model
const agentOptions: AgentOptions = {
...parentProvider !== undefined ? { provider: parentProvider } : {},
...parentModel !== undefined ? { model: parentModel } : {},
...request.agentOptions,
subagentDepth: childDepth,

View File

@@ -61,7 +61,7 @@ async function setup(script: Script, options: SetupOptions = {}) {
start: (request: SubagentStartRequest) => startInProcessRun(request, {}),
})
ctx.llm.registerAdapter(['mock'], adapter)
const parent = ctx.agentLoop.create(AgentId('parent'), { model: 'mock' })
const parent = ctx.agentLoop.create(AgentId('parent'), { provider: 'mock', model: 'mock' })
return { ctx, parent, adapter, disposeProvider }
}

View File

@@ -17,7 +17,7 @@ async function setup(script: Script) {
await ctx.plugin(AgentLoop, { agents: [] })
await ctx.plugin(SubagentService)
ctx.llm.registerAdapter(['mock'], new MockAdapter(script))
const parent = ctx.agentLoop.create(AgentId('parent'), { model: 'mock' })
const parent = ctx.agentLoop.create(AgentId('parent'), { provider: 'mock', model: 'mock' })
return { ctx, parent }
}

View File

@@ -26,7 +26,7 @@ export async function spawnHarness(workdir: string): Promise<Context> {
systemPrompt: { persona: 'You are a coding agent. Report only when the requested work is done.' },
})
await ctx.plugin(AgentLoop, { agents: [] })
await ctx.plugin(LlmDeepSeek, { models: ['deepseek-v4-flash'] })
await ctx.plugin(LlmDeepSeek)
await ctx.plugin(LocalBashExecutor, { cwd: workdir, timeoutMs: 30_000 })
await ctx.plugin(ToolBash)
await ctx.plugin(SubagentService)

View File

@@ -29,7 +29,7 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('spawn backend with-key smoke', (
it('a parent delegates to a child that writes a file on disk', async () => {
workdir = await mkdtemp(join(tmpdir(), 'dsh-subagent-spawn-e2e-'))
ctx = await spawnHarness(workdir)
const parent = ctx.agentLoop.create(AgentId('e2e-parent'), { model: 'deepseek-v4-flash' })
const parent = ctx.agentLoop.create(AgentId('e2e-parent'), { provider: 'deepseek', model: 'deepseek-v4-flash' })
parent.send([{ type: 'text', text:
'Use the subagent tool to delegate this exact task: "Use the bash tool to write the text '

View File

@@ -29,7 +29,7 @@ async function setup(script: Script) {
await ctx.plugin(SubagentService)
await ctx.plugin(spawn, { providerName: 'spawn' })
ctx.llm.registerAdapter(['mock'], adapter)
const parent = ctx.agentLoop.create(AgentId('parent'), { model: 'mock' })
const parent = ctx.agentLoop.create(AgentId('parent'), { provider: 'mock', model: 'mock' })
return { ctx, parent, adapter }
}
@@ -228,7 +228,7 @@ describe('dsh-subagent-spawn', () => {
agentId: AgentId('cwd-parent'),
sessionId: SessionId('cwd-parent-session'),
meta: { cwd: '/tmp/parent-workspace' },
agentOptions: { model: 'mock' },
agentOptions: { provider: 'mock', model: 'mock' },
})
const run = await start(ctx, 'spawn', { prompt: [{ type: 'text', text: 'p' }], parent: parentHandle.agent })
await run.result
@@ -250,7 +250,7 @@ describe('dsh-subagent-spawn', () => {
const run = await start(ctx, 'spawn', {
prompt: [{ type: 'text', text: 'p' }],
parent: parentHandle.agent,
agentOptions: { model: 'mock' },
agentOptions: { provider: 'mock', model: 'mock' },
})
const result = await run.result
expect(result.stopReason).toBe('completed')
@@ -302,7 +302,7 @@ describe('dsh-subagent-spawn', () => {
await ctx.plugin(SubagentService)
const fiber = await ctx.plugin(spawn, { providerName: 'spawn' })
ctx.llm.registerAdapter(['mock'], adapter)
const parent = ctx.agentLoop.create(AgentId('parent'), { model: 'mock' })
const parent = ctx.agentLoop.create(AgentId('parent'), { provider: 'mock', model: 'mock' })
const controller = new AbortController()
const run = await start(ctx, 'spawn', {
prompt: [{ type: 'text', text: 'q' }],
@@ -329,7 +329,7 @@ describe('dsh-subagent-spawn', () => {
await ctx.plugin(AgentLoop, { agents: [] })
await ctx.plugin(SubagentService)
const fiber = await ctx.plugin(spawn, { providerName: 'spawn' })
const parent = ctx.agentLoop.create(AgentId('parent'), { model: 'mock' })
const parent = ctx.agentLoop.create(AgentId('parent'), { provider: 'mock', model: 'mock' })
const parentEffects = parent.ctx.fiber.getEffects().length
const published: string[] = []
ctx.on('session/created', () => void published.push('session/created'))
@@ -424,7 +424,7 @@ describe('dsh-subagent-spawn', () => {
const parentHandle = await ctx.agents.create({
agentId: AgentId('doomed-parent'),
sessionId: SessionId('doomed-s'),
agentOptions: { model: 'mock' },
agentOptions: { provider: 'mock', model: 'mock' },
})
await parentHandle.dispose()
const before = ctx.agents.list().length
@@ -447,7 +447,7 @@ describe('dsh-subagent-spawn', () => {
const parentHandle = await ctx.agents.create({
agentId: AgentId('setup-race-parent'),
sessionId: SessionId('setup-race-parent-session'),
agentOptions: { model: 'mock' },
agentOptions: { provider: 'mock', model: 'mock' },
})
const published: string[] = []
ctx.on('session/created', () => void published.push('session/created'))

View File

@@ -67,8 +67,9 @@ export const Config: z<Config> = z.object({
enableRunInBackground: z.boolean().default(true),
// Prevent Schemastery from materializing omitted agentOptions as `{}`.
agentOptions: z.object({
provider: z.string(),
model: z.string(),
}).default(undefined as unknown as { model: string }),
}).default(undefined as unknown as { provider: string; model: string }),
persona: z.string(),
// Preserve omission; Schemastery's `{ allow: [] }` default would deny every tool.
toolFilter: z.object({