feat(cli-generator): send X-Fern platform-identification headers - #17516
feat(cli-generator): send X-Fern platform-identification headers#17516devin-ai-integration[bot] wants to merge 2 commits into
Conversation
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
|
Tested the platform headers end-to-end with real generated CLI binaries (no mocked runtime): built regenerated seed fixtures with HTTP — WebSocket handshake (null-type fixture + AsyncApiBinding test harness)Temporarily wired the sdk's Full demo recording in the Devin session: https://app.devin.ai/sessions/5b7fd815c5074c19a4a85820accf7f56 |
|
Also tested against a customer's real ElevenLabs specs (their openapi.json — 268 paths — plus openapi-overrides.yml and generators.yml): generated with this branch's generator via docker-mode seed run, built with
Note on WebSocket coverage for this binaryThe customer's generators.yml references an AsyncAPI spec, but Full demo recording in the Devin session: https://app.devin.ai/sessions/5b7fd815c5074c19a4a85820accf7f56 |
Description
Generated CLIs previously sent only a
User-Agent. They now send the same Fern platform-identification headers the SDK generators use, plus the invoked command, on every HTTP request and WebSocket handshake:Requested in Slack ("I noticed that the CLI doesn't send the
X-Fern-SDK-Nameheader, can we get that included?").Changes Made
sdk/src/http.rs: newHttpConfig::platform_headers()(X-Fern-Language: Rust,X-Fern-SDK-Name: <binary>-clivia the existinguser_agent_productnormalization,X-Fern-SDK-Version: CARGO_PKG_VERSION) andwith_cli_command(Option<String>)which addsX-Fern-CLI-Commandwhen the dispatch path knows the invoked command (blank/header-invalid values are dropped).build_client()installs them as reqwest default headers alongside theUser-Agent.openapi/binding.rs) and GraphQL (graphql/binding.rs) dispatch set the command from the invoked op path (_op_path.join(".")); AsyncAPI (asyncapi/binding.rs) sets it fromchannel.sdk_group_name ++ leaf_command_name, mirroringresolve_channel. Programmatic consumers without a known command send noX-Fern-CLI-Command.build_handshake_requestnow takes the platform headers and inserts them before auth headers (same override semantics asUser-Agent).generators/cli/changes/unreleased/add-fern-platform-headers.yml.seed/cli(second commit). Note: most of that diff is catch-up — the committedseed/clisnapshots were stale relative to main's generator (theUpdate Seedworkflow has been failing on main), so the regeneration also pulls in unrelated drift (e.g.jsonl/raw/httpformat docs, Cargo.lock, types-crate output).Testing
platform_headers_identify_the_cli,platform_headers_include_the_invoked_command_when_set,with_cli_command_ignores_blank_or_invalid_values, a wire-levelbuild_client_sends_platform_headers_on_the_wire(wiremock, asserts all four headers received), andhandshake_request_sets_platform_headersfor the WS path.cargo build --locked --all-features --testsandcargo test --locked --all-featuresingenerators/cli/sdk(all 1908 tests pass);pnpm seed test --generator cli --skip-scripts— 151/151 fixtures pass.Link to Devin session: https://app.devin.ai/sessions/5b7fd815c5074c19a4a85820accf7f56