Skip to content

fix(cli): keep legacy hidden selectors valid for advertise-required inputs - #2607

Open
nolanchic wants to merge 1 commit into
tutti-os:mainfrom
nolanchic:fix/builtin-invoke-validation-2193
Open

fix(cli): keep legacy hidden selectors valid for advertise-required inputs#2607
nolanchic wants to merge 1 commit into
tutti-os:mainfrom
nolanchic:fix/builtin-invoke-validation-2193

Conversation

@nolanchic

Copy link
Copy Markdown

Summary

Since #2004, Registry.Invoke validates builtin commands against their advertised schema before the handler runs. Three agentcontext commands mark agent-id as advertise-required, so the schema lists it in required — but the daemon binder deliberately treats it as optional: resolveAgentSelector accepts exactly one of --agent-id or the hidden deprecated --provider (#2193). The pre-binding validator therefore rejected the supported legacy spelling outright, and passing both selectors tripped the binder's exactly-one guard — no valid spelling was left for that path.

The AdvertisedRequired doc comment already states the intent — keep the advertised contract strict while allowing a hidden compatibility selector to satisfy runtime validation — so the fix says exactly that in the schema itself:

  • a new advertise-alt struct tag names the hidden fields that can stand in for an advertise-required field (the three commands declare advertise-alt:"provider" on agent-id)
  • Schema() emits one anyOf branch per accepted spelling ({type:"object", required:["agent-id"]}, {type:"object", required:["provider"]}) instead of a hard required entry. One branch per name matters — a single branch listing both names would require both at once. Typed object branches are required because the invocation validator only applies required to branches declaring an object type.
  • fields without an alternate render exactly as before, so no other advertised contract changes

Notes

  • Passing both selectors still reaches the handler, which rejects it with the exactly-one guard and its hint message — that error path is unchanged.
  • Cosmetic: help-text generation (command_catalog.go) reads the top-level required list, so agent-id now shows as optional in generated help. The anyOf constraint is not reflected there; happy to follow up if the help generator should learn about alternates.

Test plan

  • TestStartCommandSchemaPassesInvocationValidationForLegacySelector e2e — the real start command through NewRegistryFromProvidersInvoke: canonical and legacy spellings pass the pre-binding validator, neither present is rejected
  • TestSchemaRendersAnyOfForAdvertisedRequiredWithAlternate — one branch per spelling, hidden field stays out of properties
  • TestSchemaKeepsHardRequiredForAdvertisedRequiredWithoutAlternate — no-alternate fields unchanged
  • TestRegistryInvokeAcceptsLegacyAlternateForAdvertisedRequired — validator-level coverage
  • Updated TestStartCommandRequiresOneSelectorAndPrompt / TestAgentStartCommandAllowsOmittedModel to the new advertised shape
  • go test ./service/cli/... — 11 packages ok; full ./service/... — 42 packages ok; gofmt clean; ValidateCapabilityInputSchema accepts the new shape

Fixes #2193

…nputs

Since tutti-os#2004, Registry.Invoke validates builtin commands against their
advertised schema before the handler runs. Three agentcontext commands
mark agent-id as advertise-required, so the schema lists it in
required while the daemon binder deliberately treats it as optional:
resolveAgentSelector accepts exactly one of agent-id or the hidden
deprecated provider. The invocation validator therefore rejected the
supported legacy spelling outright, and passing both selectors tripped
the binder's exactly-one guard — no valid spelling was left.

AdvertisedRequired keeps the advertised contract strict while allowing
a hidden compatibility selector to satisfy runtime validation, so say
so in the schema itself: a new advertise-alt tag names the hidden
fields that can stand in, and Schema renders one anyOf branch per
accepted spelling (typed object branches, which the invocation
validator already supports) instead of a hard required entry. One
branch per name matters: a single branch listing both names would
require both at once. Fields without an alternate keep rendering
exactly as before.

The advertised capability contract for the three commands now states
the real constraint — one of agent-id or the deprecated provider —
which is also what external schema consumers should see.

Fixes tutti-os#2193

Signed-off-by: Nolan <nolanchic@gmail.com>
@tutti-pr-review-bot
tutti-pr-review-bot Bot requested a review from a team August 25, 2026 13:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(cli): advertise-required flags are enforced at invocation, breaking the legacy --provider path

1 participant