Repository navigation
feat(mcp,cli): virtual models in the MCP tools and the thinker CLI - #190
Conversation
Fifth PR of the ADR 0004 delivery plan (#176). - MCP: thinker_routing_virtual_list, _create (name, model with optional provider/auth_type/key_label pins, fallbacks, continue_on_default, response_mode), _update (rename, primary, fallbacks with [] to clear, clear_model, continue_on_default, response_mode, enabled; route writes first) and _delete, found by name ignoring case or by id. Write tools follow the mcp:write rule of the existing ones. - thinker_routing_status lists the virtual models; thinker_routing_test accepts a virtual model name in model and reports routing_reason and virtual_model from the X-Thinker-* response headers. - Model params: RouteModelParamsService takes a tier name or { virtual: <name> } and resolves the virtual model by name (case- insensitive) to the virtual:<id> scope; only its own chain is addressable. thinker_routing_params_get/_set gain a virtual field, exclusive with tier. New REST endpoint GET|PATCH /api/v1/routing/:agent/virtual-model-params?virtual=&model=; the scope-keyed /model-params endpoint already accepts virtual:<id>. - CLI: thinker routing virtual list|create|update|delete|enable|disable (--model, repeatable --fallback, --continue-on-default, delete needs --yes); routing status includes virtual models; routing test --model <virtual> shows the virtual model and reason; routing params get|set --virtual, exclusive with --tier. - Skill (SKILL.md + regenerated skill-content.gen.ts), MCP operating guide and docs/dev/guia.md updated. - Tests: MCP tool and params service/controller unit tests, CLI unit tests, and an e2e spec driving the routing tools against the real services and database (validation, 409, virtual:<id> params, REST readback, update, delete cleanup, tenant isolation). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Revisão: PR #190 (modelos virtuais no MCP, na CLI e no endpoint de parâmetros por nome; PR 5 da ADR 0004)Escopo
Histórico: está limpo. Há um único commit ( CI no SHA revisado (check-runs do commit): os 19 checks estão verdes:
Critérios de risco alto: nenhum se aplica. O PR não mexe em auth, cripto, credenciais nem migração, e não enfraquece o isolamento. Conferido contra as seções 9 e 12 da ADRFerramentas
Permissões MCP
Isolamento
CLI
Escopo dos parâmetros: Divergências declaradas
Should-fix1.
Nits1. A atualização em vários passos não é atômica ( 2. Assimetria com a API administrativa: 3. ResumoNão há blocker nem critério de risco alto. Fica um should-fix, que precisa ser corrigido ou virar issue com o link registrado no PR antes do merge. O CI completo está verde neste SHA. O merge também depende do Head revisado: cbafbf6 |
Addresses the review of #190. - thinker_routing_status: enabled/reason stay the shared auto verdict (status_for: "auto"; RoutingStatus and the dashboard endpoint are unchanged). New routes_by_virtual_model and active_virtual_models (enabled, with a route of their own or continuing on a routable Default). When only virtual models can route, reason becomes auto_not_routable and auto_reason keeps the auto cause. No active provider still reports no_provider with no active virtual models. - thinker routing status: the same two fields. - Virtual model update (MCP and CLI): the writes are separate calls, not one transaction. A taken name (and, in MCP, an invalid one) is refused before any write, and a failure after an earlier write now lists the steps already applied. Comments and the tool description say so. - Changeset notes that RouteModelParamsView.tier is now optional; skill, regenerated skill content and docs/dev/guia.md updated. - Unit tests for both status cases and the partial update; e2e covers the only-virtual and auto-routable status cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found by qa-docker on #190: `routing params --virtual v --model fake2/gpt-4o` answered 400 because the chain stores the custom provider's internal id (custom:<id>/gpt-4o), while virtual create and update accept the public one. - RouteModelParamsService matches `model` against each route's stored id, its public id (openAiModelId of the agent's catalog entry, e.g. <alias>/<model>), and its native id with or without the provider prefix. All names are matched in one pass, so a native id two connections of the chain share is reported as ambiguous, naming the public ids to use. Applies to tiers and virtual models alike. - The view adds public_model and public_models next to route and models; the not-routed error shows a custom route's public id. - Callers (REST controller, MCP params tools) pass the agent's tenant so the catalog can be read; a catalog read failure falls back to route-derived names. - Unit tests for public/native/stored ids, ambiguity, tiers and the missing-catalog paths; e2e with an aliased custom provider in a virtual chain. Skill, changeset and docs/dev/guia.md updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-revisão: PR #190 (head
|
…tability Addresses the second review of #190 (head 2501ecc). - Params model selector: match in layers and stop at the first with a hit: (1) the stored id (Anthropic short ids normalized), (2) the public id, (3) the derived native names. An id that names one route exactly (e.g. OpenRouter's stored "openai/gpt-4o") is no longer made ambiguous by another route's derived name. Ambiguity is only declared inside the winning layer, and the error suggests only names (public id, then stored id) that select a single connection. - Virtual model views gain `routable`, computed with virtualModelRoutable on the chain the proxy builds (own routes, then only the `default` slot with continue_on_default: override, legacy auto-assigned route or an available fallback), filtered by the catalog snapshot like context_length. thinker_routing_status and `thinker routing status` both derive routes_by_virtual_model and active_virtual_models from it, so an empty default slot with routes in another slot no longer reads as routable. - Tests: layered matching for virtual models and tiers, unique-only suggestions, virtualModelRoutable rules, MCP/CLI status from the flag, and an e2e with an empty default slot and a routed `simple` slot. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-revisão: PR #190 (head
|
|
O should-fix da terceira revisão ( |
* chore(release): version 0.1.2 Bump the thinker version package to 0.1.2 and consume the pending virtual model changesets (ADR 0004, #176: #186, #187, #188, #190, #191, #198, #199, #200) into the changelog, ordered by part. Finalize the PT-BR release notes in docs/releases/0.1.2.md: drop the draft marker and add #199 (routable and context_length ignore disconnected providers) and #200 (409 guard for providers used by virtual models, keyLabel pins follow key rename and deletion). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(release): address review nits on the 0.1.2 notes and changelog - Release notes: qualify the upgrade note; context_length on auto, the per-attempt request_params fix and the optional RouteModelParamsView.tier apply even without virtual models. - Release notes: drop the stray blank line in the "Corrigido" list. - CHANGELOG: link the PT-BR release notes from the 0.1.2 entry, as the 0.1.1 entry does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
PR 5 of the ADR 0004 delivery plan (#176): virtual models in the MCP tools and the
thinkerCLI.What changes
MCP (
packages/backend/src/mcp/tools/virtual-models.tools.ts,routing.tools.ts)thinker_routing_virtual_list,thinker_routing_virtual_create(name,modelwith optionalprovider/auth_type/key_label,fallbacks,continue_on_default,response_mode),thinker_routing_virtual_updateandthinker_routing_virtual_delete. Update and delete find the virtual model by name (ignoring case) or by id._updatechanges only the fields it receives:modelreplaces the primary,fallbacksreplaces the list ([]clears it),clear_modelremoves the primary and its fallbacks, plusname,continue_on_default,response_modeandenabled. Route writes go first, so a rejected route leaves the other fields unchanged.mcp:write, like the existing ones.thinker_routing_statuslists the virtual models (id, name, enabled, route, fallbacks,continue_on_default,response_mode).thinker_routing_testaccepts a virtual model name inmodel. It reportsrouting_reasonandvirtual_model, read fromX-Thinker-ReasonandX-Thinker-Virtual-Model.thinker_routing_params_get/_setgain avirtualfield, exclusive withtier.Model params
RouteModelParamsServicetakes either a tier name or{ virtual: <name> }. It resolves the virtual model by name, ignoring case, to thevirtual:<id>scope.tier:default, as in ADR section 9.GET|PATCH /api/v1/routing/:agent/virtual-model-params?virtual=<name>&model=<id>, next totiers/:tier/model-params. The name goes in the query string because it may contain/.PUT|DELETE /model-paramsendpoint already acceptedscope: "virtual:<id>". An e2e test now covers it.CLI (
packages/cli/src/commands/routing.ts)thinker routing virtual list|create|update|delete|enable|disable:createtakes--name,--model(with optional--provider,--auth-type,--key-label), repeatable--fallback,--continue-on-defaultand--response-mode;updatetakes--name,--model,--fallback,--clear-fallbacks,--clear-model,--continue-on-default/--no-continue-on-defaultand--response-mode;deleterequires--yes, likerouting custom delete.routing statusnow includesvirtual_models.routing test --model <virtual>showsvirtual_modelandrouting_reason.routing params get|set --virtual <name>is exclusive with--tier.Docs
packages/cli/skill/SKILL.md) and the regeneratedsrc/skill-content.gen.ts.docs/dev/guia.md, routing section.The proxy resolution,
/v1/modelsand the frontend are unchanged.Divergences from the ADR
create/updatealso accept--provider,--auth-type,--key-labeland--response-mode.updatealso accepts--name,--clear-fallbacks,--clear-modeland--no-continue-on-default, so the last two can be undone. The MCP tools have the matching fields.virtual:<id>scope". The scope-keyed endpoint already did. Name-based access needed a new endpoint,virtual-model-params, because the tier-addressed path cannot carry a virtual model name.Checks (local; CI pending #38)
npm run lint: 0 errors. The 383 warnings were there before this PR; the changed files have none.tsconfig.test.json) and cli all clean.nest build) and cli (gen+tsc) all OK.TZ=UTC npm run test:e2e:docker, disposablepostgres:16-alpine): 79 suites, 715 tests passed. This includes the newtest/virtual-models-mcp.e2e-spec.ts.npm run check:changesets: OK.QA
qa-dockershould run: the PR changes runtime behavior of the MCP server, the CLI and a new REST endpoint.🤖 Generated with Claude Code