test(web-search): adapt fixtures to master's model selection and projections

Master moved the step's model route into the assembly context: the agent loop
fixes it per step and registers the prompt's provider variable from it, and
installModelSelection no longer takes a mutable selection. The tool-web
readiness fixture now registers that variable and passes the step's
modelSelection to each assembly.

AgentRegistry now needs the session projection registry, so the
web-search-deepseek initiator fixtures and the Loader composition in
chat-endpoint.spec.ts mount it, as master's own fixtures in this package do.
This commit is contained in:
Yichen Jiang committed 2026-10-21 14:53:05 +08:00
1 parent 7a75f225c5
commit 2548bb4acf
3 files changed
+14 -12

No files matched your search

+9 -12
View File
@@ -1,6 +1,6 @@
import { afterEach, describe, expect, it, vi } from 'vitest'
import { Context } from '@deepseek-ai/cordis'
import { installModelSelection, type ModelSelectionRef } from '@deepseek-ai/dsh-agent'
import type { ModelSelection } from '@deepseek-ai/dsh-agent'
import { createScope, type Scope } from '@deepseek-ai/dsh-scope'
import TurndownService from 'turndown'
import { ToolCallId } from '@deepseek-ai/dsh-llm'
@@ -1086,26 +1086,23 @@ describe('web_search offering per model request', () => {
}
/**
* Mount the real prompt, tool, and web services with tool-web. Model selection is
* installed first, the order a tool-web reload produces once a Session exists.
* Mount the real prompt, tool, and web services with tool-web. The prompt's `provider`
* variable comes from the step's model selection, as the agent loop registers it.
* @param setup - registered providers, the configured search provider, and the selected route.
* @returns the Session's model selection, tool-web's fiber, and a reader for one model request.
* @returns the step's model selection, tool-web's fiber, and a reader for one model request.
*/
async function compose(setup: { providers: WebSearchProvider[]; searchProvider?: string; route?: string }) {
const ctx = new Context()
mounted.push(ctx)
const selection: ModelSelectionRef = {
current: { provider: setup.route ?? 'deepseek-official', model: 'deepseek-v4-flash' },
assembled: undefined,
}
installModelSelection(ctx, selection)
const selection: ModelSelection = { provider: setup.route ?? 'deepseek-official', model: 'deepseek-v4-flash' }
await ctx.plugin(SystemPrompt)
ctx.systemPrompt.variable('provider', context => context.modelSelection?.provider)
await ctx.plugin(ToolRuntime)
await ctx.plugin(WebRuntime, setup.searchProvider === undefined ? {} : { searchProvider: setup.searchProvider })
for (const provider of setup.providers) ctx.web.registerSearchProvider(provider)
const fiber = await ctx.plugin(ToolWeb, {})
const request = async (): Promise<{ tools: string[]; prompt: string }> => {
const assembly = await ctx.systemPrompt.assemble({})
const assembly = await ctx.systemPrompt.assemble({ modelSelection: { ...selection } })
return { tools: assembly.tools.map(tool => tool.name), prompt: renderPrompt(assembly) }
}
return { ctx, selection, fiber, request }
@@ -1141,9 +1138,9 @@ describe('web_search offering per model request', () => {
it('follows the model selected for each request', async () => {
const { selection, request } = await compose({ providers: [routeProvider('deepseek', ['deepseek-account'])], route: 'deepseek-account' })
expect((await request()).tools).toContain('web_search')
selection.current = { provider: 'deepseek-official', model: 'deepseek-v4-flash' }
selection.provider = 'deepseek-official'
expect((await request()).tools).not.toContain('web_search')
selection.current = { provider: 'deepseek-account', model: 'deepseek-v4-flash' }
selection.provider = 'deepseek-account'
expect((await request()).tools).toContain('web_search')
})
@@ -17,6 +17,7 @@ import { createLaunchEnvironmentSnapshot } from '@deepseek-ai/dsh-launch-environ
import LlmRuntime from '@deepseek-ai/dsh-llm'
import * as Official from '@deepseek-ai/dsh-llm-deepseek-api-key'
import SessionStore, { SessionId } from '@deepseek-ai/dsh-session'
import SessionProjectionRegistry from '@deepseek-ai/dsh-session-projection'
import WebRuntime from '@deepseek-ai/dsh-web'
import * as deepseekPlugin from '@deepseek-ai/dsh-web-search-deepseek'
@@ -55,6 +56,7 @@ async function compose(composition: Composition): Promise<Context> {
const rows = [
{ id: 'llm', name: '@deepseek-ai/dsh-llm' },
{ id: 'session', name: '@deepseek-ai/dsh-session' },
{ id: 'session-projection', name: '@deepseek-ai/dsh-session-projection' },
{ id: 'agents', name: '@deepseek-ai/dsh-agent' },
{
id: 'llm-deepseek', name: '@deepseek-ai/dsh-llm-deepseek-api-key',
@@ -67,6 +69,7 @@ async function compose(composition: Composition): Promise<Context> {
await writeFile(configPath, JSON.stringify(rows))
const modules = new Map<string, unknown>([
['@deepseek-ai/dsh-llm', LlmRuntime], ['@deepseek-ai/dsh-session', SessionStore],
['@deepseek-ai/dsh-session-projection', SessionProjectionRegistry],
['@deepseek-ai/dsh-agent', AgentRegistry], ['@deepseek-ai/dsh-llm-deepseek-api-key', Official],
['@deepseek-ai/dsh-web', WebRuntime], ['@deepseek-ai/dsh-web-search-deepseek', deepseekPlugin],
])
@@ -913,6 +913,7 @@ describe('web-search-deepseek search readiness', () => {
expect(await ctx.web.searchReady('deepseek-account')).toBe(false)
// A search on that route reads the same grant before any key and fails instead of trying the key.
await ctx.plugin(SessionStore)
await ctx.plugin(SessionProjectionRegistry)
await ctx.plugin(AgentRegistry)
const session = ctx.sessions.create(SessionId('web-search-unreadable-grant'))
session.append('turn/start', { turn: 1 })
@@ -939,6 +940,7 @@ describe('web-search-deepseek route policy', () => {
const ctx = new Context()
try {
await ctx.plugin(SessionStore)
await ctx.plugin(SessionProjectionRegistry)
await ctx.plugin(AgentRegistry)
await ctx.plugin(WebRuntime, { searchProvider: DEEPSEEK_PROVIDER_ID })
await ctx.plugin(deepseekPlugin, config)