Skip to content

feat: let callers set the agent at the start of the User-Agent header - #425

Merged
alxhill merged 7 commits into
mainfrom
feat/custom-user-agent
Nov 12, 2026
Merged

alxhill merged 7 commits into
mainfrom
feat/custom-user-agent

Conversation

@smithednominal

@smithednominal smithednominal commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

Usage reporting groups requests by the first agent in the User-Agent header, which was always nominal-streaming. Connectors built on this crate could not be told apart.

Goal: allow every connector using code derived from this library to report a full user agent chain, e.g. nominal-matlab/0.3.0 nominal-streaming/0.10.7 ....

Changes

  • Add ProductAgent, a validated program name and version. ProductAgent::default() is nominal-streaming/<crate version>.
  • Add a user_agent: ProductAgent option on NominalStreamOpts (with with_user_agent) and NominalLogStreamOpts. With the default, the header is unchanged. With any other agent, the header starts with <name>/<version> nominal-streaming/<crate version>.
  • ProductAgent::new returns Result<Self, ProductAgentError>. The HTTP client panics on a name it rejects and silently sends a version it rejects as 0.0.0, so both are rejected up front:
    • a name starts with an ASCII letter and contains only ASCII letters, digits and hyphens;
    • a version is dot-separated numbers, optionally followed by -rcN and a git describe suffix such as -5-gabc123. Suffixes like -dirty or -beta.1 are not accepted.
  • Python: PyNominalStreamOpts and PyNominalLogStreamOpts gain with_user_agent(name, version), which raises ValueError for an invalid name or version, and a user_agent property returning name/version.

Breaking changes

These client constructors now take the agent as an argument:

  • NominalApiClients::try_from_url(base_url, &ProductAgent)
  • async_conjure_streaming_client(uri, &ProductAgent)
  • async_conjure_client(service, uri, &ProductAgent)

NominalApiClients::from_uri is unchanged and uses the default agent. Pass &ProductAgent::default() to keep the previous behaviour elsewhere.

Testing

  • cargo test --workspace
  • cargo clippy --all-targets --all-features
  • just python dev && just python test && just python check

smithednominal and others added 2 commits November 6, 2026 17:38
Usage reporting groups requests by the first agent in the User-Agent
header, which was always nominal-streaming. Connectors built on this
crate could not be told apart.

Add ProductAgent and a user_agent option on NominalStreamOpts and
NominalLogStreamOpts, plus NominalApiClients::try_from_url_with_agent
for upload and ingest callers. A set agent comes first, followed by
nominal-streaming/<crate version>. Without one, the header is unchanged.

ProductAgent::new never fails. Names and versions the HTTP client would
reject are changed to the closest accepted value, with a warning,
because the client panics on invalid names and sends invalid versions
as 0.0.0.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add with_user_agent(name, version) and a user_agent property to
PyNominalStreamOpts and PyNominalLogStreamOpts.

Review fixes:
- Ignore an agent whose name has no letters instead of sending "unknown".
- Log the cleanup warning when clients are built, after logging is set up.
- Keep -rcN and git-describe suffixes followed by other text.
- Turn each run of rejected name characters into one hyphen.
- Borrow the agent in try_from_url_with_agent.
- Say which streams NominalStreamOpts::user_agent applies to.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@smithednominal
smithednominal marked this pull request as ready for review November 7, 2026 00:34
Comment thread nominal-streaming/src/log/consumer.rs Resolved
Comment thread nominal-streaming/src/log/mod.rs Resolved
Comment thread nominal-streaming/src/client.rs Resolved
Comment thread nominal-streaming/src/client.rs Resolved
@alxhill

alxhill commented Nov 12, 2026

Copy link
Copy Markdown
Contributor

@smithednominal thx for the PR! updated it with a cleaner structure, will merge and release now

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.

2 participants