mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
feat(llm): route adapters by provider
This commit is contained in:
@@ -37,7 +37,7 @@ async function setup(script: Script) {
|
||||
await ctx.plugin(spawn, { providerName: 'spawn' })
|
||||
await ctx.plugin(WorkerWorkflowEngine, {})
|
||||
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 }
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ describe('validateMeta', () => {
|
||||
description: 'migrate call sites',
|
||||
whenToUse: 'large mechanical sweeps',
|
||||
phases: [
|
||||
{ title: 'Discover' },
|
||||
{ title: 'Discover', provider: 'openai' },
|
||||
{ title: 'Transform', detail: 'one agent per file', model: 'deepseek-v4-pro' },
|
||||
],
|
||||
})
|
||||
@@ -42,7 +42,7 @@ describe('validateMeta', () => {
|
||||
description: 'migrate call sites',
|
||||
whenToUse: 'large mechanical sweeps',
|
||||
phases: [
|
||||
{ title: 'Discover' },
|
||||
{ title: 'Discover', provider: 'openai' },
|
||||
{ title: 'Transform', detail: 'one agent per file', model: 'deepseek-v4-pro' },
|
||||
],
|
||||
})
|
||||
@@ -73,6 +73,7 @@ describe('validateMeta', () => {
|
||||
expectInvalid({ name: 'x', description: 'd', phases: [{ title: '' }] }, 'meta.phases[0].title must be a non-empty string')
|
||||
expectInvalid({ name: 'x', description: 'd', phases: [{ title: 'Scan', order: 1 }] }, 'meta.phases[0].order is not a recognized field')
|
||||
expectInvalid({ name: 'x', description: 'd', phases: [{ title: 'Scan', detail: 9 }] }, 'meta.phases[0].detail must be a string')
|
||||
expectInvalid({ name: 'x', description: 'd', phases: [{ title: 'Scan', provider: 9 }] }, 'meta.phases[0].provider must be a string')
|
||||
expectInvalid({ name: 'x', description: 'd', phases: [{ title: 'Scan', model: 9 }] }, 'meta.phases[0].model must be a string')
|
||||
})
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ interface FakeHost {
|
||||
|
||||
interface FakeHostOptions {
|
||||
/** Auto-respond to child-start: reply started + settled per child index. Omit a reply to leave the child pending. */
|
||||
reply?: (request: { prompt: string; schema?: unknown; model?: string }, index: number) => ChildResult | undefined
|
||||
reply?: (request: { prompt: string; schema?: unknown; provider?: string; model?: string }, index: number) => ChildResult | undefined
|
||||
/** Reject the start instead (child-start-error) when returning a string. */
|
||||
refuse?: (index: number) => string | undefined
|
||||
/** Auto-send `go` on `ready` (default true). */
|
||||
@@ -143,6 +143,17 @@ describe('runWorkerSession over an in-process MessageChannel', () => {
|
||||
host.close()
|
||||
})
|
||||
|
||||
it('agent({provider}) forwards a provider without inventing a model', async () => {
|
||||
const host = fakeHost({ reply: () => text('ok') })
|
||||
void runWorkerSession(host.port, init("return await agent('route me', { provider: 'openai' })"))
|
||||
const result = await host.result()
|
||||
expect(result.value).toBe('ok')
|
||||
const start = host.ofType(WorkerToHostType.ChildStart)[0]!
|
||||
expect(start.request.provider).toBe('openai')
|
||||
expect(start.request.model).toBeUndefined()
|
||||
host.close()
|
||||
})
|
||||
|
||||
it('a schema child completing WITHOUT a structured value resolves null with a failed outcome', async () => {
|
||||
const host = fakeHost({ reply: () => text('prose, no structure') })
|
||||
void runWorkerSession(host.port, init("return await agent('p', { schema: { type: 'object' } })"))
|
||||
|
||||
@@ -35,7 +35,7 @@ async function harness(): Promise<Context> {
|
||||
await built.plugin(ToolRegistry)
|
||||
await built.plugin(AgentRegistry)
|
||||
await built.plugin(AgentLoop, { agents: [] })
|
||||
await built.plugin(LlmDeepSeek, { models: ['deepseek-v4-flash'] })
|
||||
await built.plugin(LlmDeepSeek)
|
||||
await built.plugin(SubagentService)
|
||||
await built.plugin(Spawn, { providerName: 'spawn' })
|
||||
await built.plugin(WorkerWorkflowEngine, { provider: 'spawn' })
|
||||
@@ -64,7 +64,7 @@ describe.skipIf(!process.env.DEEPSEEK_API_KEY)('worker workflow engine with-key
|
||||
const parentHandle = await ctx.agents.create({
|
||||
agentId: AgentId('wf-worker-e2e-parent'),
|
||||
sessionId: 'wf-worker-e2e-session' as never,
|
||||
agentOptions: { model: 'deepseek-v4-flash' },
|
||||
agentOptions: { provider: 'deepseek', model: 'deepseek-v4-flash' },
|
||||
})
|
||||
|
||||
const events: string[] = []
|
||||
|
||||
@@ -236,6 +236,14 @@ describe('dsh-workflow-workerthread', () => {
|
||||
expect(provider.runs[0]!.request.parent).toBeDefined()
|
||||
})
|
||||
|
||||
it('agent({provider}) forwards provider-only agentOptions across the thread', async () => {
|
||||
const { ctx, parent, provider } = await setup()
|
||||
const result = await run(ctx, parent, scripted("return await agent('route me', { provider: 'openai' })"))
|
||||
|
||||
expect(result.value).toBe('stub reply')
|
||||
expect(provider.runs[0]!.request.agentOptions).toEqual({ provider: 'openai' })
|
||||
})
|
||||
|
||||
it('a fatal hook error inside the worker kills the script and reports the error', async () => {
|
||||
const { ctx, parent } = await setup()
|
||||
const result = await run(ctx, parent, scripted("return await parallel([() => agent('x', { isolation: 'worktree' })])"))
|
||||
|
||||
Reference in New Issue
Block a user