| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- /** Model-facing discovery of LLM routes available to child Agents. */
- import type { Context } from '@deepseek-ai/cordis'
- import type LlmRuntime from '@deepseek-ai/dsh-llm'
- import type { LlmProviderInfo } from '@deepseek-ai/dsh-llm'
- import { defineTool } from '@deepseek-ai/dsh-tools'
- import type { ModelSelectionPolicy } from './model-selection.ts'
- interface ListSubagentModelsRequest {
- readonly provider?: string
- readonly model?: string
- }
- /** Resolve one registered provider with a model-correctable diagnostic. */
- function registeredProvider(
- llm: LlmRuntime,
- policy: ModelSelectionPolicy,
- providerId: string,
- ): LlmProviderInfo {
- const providers = llm.listProviders()
- const provider = providers.find(candidate => candidate.id === providerId)
- if (provider !== undefined) return provider
- const available = providers
- .filter(candidate => policy.routes.some(route => route.provider === candidate.id))
- .map(candidate => candidate.id)
- .join(', ') || '(none)'
- throw new Error(`LLM provider "${providerId}" is not registered; available providers: ${available}`)
- }
- /** Render one advertised or resolved model. */
- function modelLine(provider: string, model: { id: string; name: string; description?: string }): string {
- return `${provider}/${model.id} — ${model.name}${model.description === undefined ? '' : `: ${model.description}`}`
- }
- /** Read the requested provider, advertised models, or exact-model efforts. */
- async function listSubagentModels(
- ctx: Context,
- policy: ModelSelectionPolicy,
- request: ListSubagentModelsRequest,
- signal: AbortSignal,
- ): Promise<string> {
- const llm = ctx.get('llm')
- if (llm === undefined) {
- throw new Error('cannot discover child LLM routes because the `llm` service is unavailable')
- }
- if (request.model !== undefined && request.provider === undefined) {
- throw new Error('`model` requires `provider`')
- }
- if (request.provider === undefined) {
- const providers = llm.listProviders()
- .filter(provider => policy.routes.some(route => route.provider === provider.id))
- return providers.length === 0
- ? '(no LLM providers)'
- : providers.map(provider => `${provider.id} — ${provider.name}`).join('\n')
- }
- if (request.provider.length === 0) throw new Error('`provider` must be non-empty')
- const allowedRoutes = policy.routes.filter(route => route.provider === request.provider)
- if (allowedRoutes.length === 0) {
- throw new Error(`LLM provider "${request.provider}" is not allowed for this Session`)
- }
- const provider = registeredProvider(llm, policy, request.provider)
- if (request.model === undefined) {
- const models = (await llm.listModels(provider.id))
- .filter(model => allowedRoutes.some(route => route.model === model.id))
- return models.length === 0
- ? `(no advertised models for ${provider.id})`
- : models.map(model => modelLine(provider.id, model)).join('\n')
- }
- if (request.model.length === 0) throw new Error('`model` must be non-empty')
- if (!allowedRoutes.some(route => route.model === request.model)) {
- throw new Error(`child LLM route "${provider.id}/${request.model}" is not allowed for this Session`)
- }
- const model = await llm.resolveModelInfo(provider.id, request.model, signal)
- const efforts = model.reasoning?.efforts.map(effort => (
- `${effort.id}${model.reasoning?.defaultEffort === effort.id ? ' (default)' : ''} — ${effort.name}`
- + (effort.description === undefined ? '' : `: ${effort.description}`)
- )).join('\n') || '(no advertised reasoning efforts)'
- return `${modelLine(provider.id, model)}\nReasoning efforts:\n${efforts}`
- }
- /**
- * Register `list_subagent_models` for one owning delegation-tool instance.
- * @param ctx - Context whose tool registry owns the fixed discovery definition.
- * @param policy - Route policy captured for this Session.
- */
- export function registerListSubagentModels(ctx: Context, policy: ModelSelectionPolicy): void {
- ctx.tools.register(defineTool({
- name: 'list_subagent_models',
- description:
- 'Discover LLM routes for subagents without changing the current Agent. Call with no arguments to list '
- + 'registered providers, with `provider` to list its advertised models, or with `provider` and `model` '
- + 'to inspect that exact model and its reasoning efforts. Catalog membership is advisory: an adapter may '
- + 'accept an unlisted model id. Use the returned ids with a delegation tool\'s `provider`, `model`, and '
- + '`reasoning_effort` fields.',
- parameters: {
- provider: {
- type: 'string',
- description: 'Registered LLM provider id. Omit to list providers.',
- },
- model: {
- type: 'string',
- description: 'Exact model id to inspect. Requires provider; omit to list that provider\'s advertised models.',
- },
- },
- output: {
- schema: { type: 'string' },
- render: (_args, result) => [{ type: 'text', text: result }],
- },
- execute(args, exec) {
- return listSubagentModels(ctx, policy, args, exec.signal)
- },
- }))
- }
|