fix(cli-generator): disclose the flag name for every property in --schema - #17554
Merged
Conversation
…hema
Both regression agents independently reported the same gap, and it left one
operation whose advertised contract could not be followed at all.
`--schema` keys properties by wire name, and the flag diverges more often than
it looks. A header `Idempotency-Key` is registered as `--idempotency-key`; an
`x-fern-parameter-name` rename changes it outright; and a name colliding with a
builtin gets a `-param` suffix — so a spec parameter called `query` becomes
`--query-param`, because `--query` is the JMESPath global. On
`conversational-ai knowledge-base search` that meant `required` named `query`
while no `--query` flag existed for it:
$ elevenlabs conversational-ai knowledge-base search --query x --dry-run
Required parameter 'query' is missing. Provide it via --query-param or --params
An agent had to reimplement the CLI's own sanitisation to get from a property
name to a flag, and get the `-param` suffix and header kebab-casing right. It
now reads the flag off the contract. Derived from the same
`resolve_param_flag_name` the command builder uses, so the two cannot drift;
absent only when the name cannot be sanitised into a flag at all, which is
itself the useful signal that the parameter is reachable via `--params` alone.
Multipart fields get the same treatment.
This is the parameter-loop counterpart to the builtin-collision skip the
multipart commit added — one loop in `build_operation_schema` was honest about
builtin collisions and the other was not.
Verified on the ElevenLabs spec: 2364 settable properties across 337
operations, 0 missing a `flag`, and the previously-unfollowable operation now
exits 0 from exactly what the contract advertises.
There was a problem hiding this comment.
AI Review Summary
Adds a flag field to each settable property in the --schema output, derived from resolve_param_flag_name for parameters and a local kebab for multipart fields. The refactor of the else if into else + a separate variable_reference.is_none() && required check preserves the original required-list semantics. Two issues: an unused closure parameter in the new test (compile warning), and the multipart flag being computed locally rather than via a shared resolver.
- 🟡 2 warning(s)
- 🔵 1 suggestion(s)
To request another review, comment /ai-review on this pull request.
iamnamananand996
approved these changes
Aug 28, 2026
Address review: dedup cross-parameter flag collisions the same way build_resource_command does, route multipart flags through a shared resolver, and trim the parameter-loop comment. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Linear ticket: Refs
Follow-up to #17545, which merged while this was in flight. Both regression agents that verified #17545 independently reported the same gap, and it left one operation whose advertised contract could not be followed at all.
--schemakeys properties by wire name, and the flag diverges more often than it looks:Idempotency-Key--idempotency-keyquery--query-param--queryis the JMESPath global, so the spec param gets a-paramsuffixx-fern-parameter-namerenameThe
querycase made the contract literally unfollowable onconversational-ai knowledge-base search—input.requirednamedquery, and no--queryflag existed for it:An agent had to reimplement the CLI's own sanitisation to get from a property name to a flag — and get the
-paramsuffix and header kebab-casing right. It now reads the flag off the contract:Derived from the same
resolve_param_flag_namethe command builder uses, so the two cannot drift. Multipart fields get the same treatment.flagis absent exactly when the builder registers no flag, which is itself the signal that the property is reachable via--paramsalone. That is two cases, both mirroringbuild_resource_command:flag_to_wiremap over the same sorted iteration — otherwise the loser would advertise a flag that sets the winner's parameter.This is the parameter-loop counterpart to the builtin-collision skip #17545's multipart commit added: one loop in
build_operation_schemawas honest about builtin collisions and the other was not.input.requiredstill uses wire names, so the--paramsroute keeps working unchanged.Changes Made
sdk/src/openapi/help.rs— emitflagper settable property (parameters and multipart fields); skip it for sdk-variable-bound params, which already advertiseglobalFlag, and for params whose flag was claimed by an earlier wire name.sdk/src/openapi/commands.rs— newresolve_multipart_field_flag_name, called by both the command builder and the help loop. This also closed an existing drift: the builder skipped onis_reserved_flag_name(builtins plus a customer-configureduserAgentSuffixFlag) while the help loop only checkedBUILTIN_FLAG_NAMES, so a field colliding with the suffix flag was advertised with a flag that is never registered.generators/cli/changes/unreleased/.Testing
1945 lib tests pass.
every_settable_property_discloses_its_flagcovers the builtin-collision suffix, header kebab-casing, an ordinary name, a multipart field, and a cross-parameter collision (pageSize/page_sizeboth resolving to--page-size: the winner discloses it, the loser has noflag), and assertsrequiredstill uses wire names.Verified by regenerating and building the ElevenLabs CLI: 2364 settable properties across 337 operations, 0 missing a
flag, and the previously-unfollowable operation now exits 0 from exactly what the contract advertises (--query-param x→query_params=[['query','x']]).Also re-confirmed on the same build: 0 ancestor-prefix violations in any
requiredlist.Link to Devin session: https://app.devin.ai/sessions/8d3395b13c124d728dc5d615e2149057
Open in Devin Desktop: https://app.devin.ai/desktop/session/8d3395b13c124d728dc5d615e2149057?variant=devin