feat: attribute requests to a user profile - #33
Merged
Merged
Conversation
dtmeadows-ant
previously approved these changes
Sep 9, 2026
sophie-ant
dismissed
dtmeadows-ant’s stale review
September 9, 2026 17:36
The base branch was changed.
Lets an app attribute each request to one of its users. Set
`userProfileID:` on `ClaudeLanguageModel`, and every request sends the
`anthropic-user-profile-id` header, with the `user-profiles-2026-08-18`
beta that the header needs:
ClaudeLanguageModel(name: .opus5, auth: auth, userProfileID: profileID)
Until now `.apiKey` and `.appAttest` couldn't send the header at all,
and `.proxied` needed both headers set by hand.
- The executor sets the header and adds the beta to the list it already
merges, so the beta goes after any values the request already
carries, such as a proxy's or the fallbacks beta, and is never
repeated.
- The configured profile replaces a proxy header of the same name,
however it's spelled, so a request carries one profile.
- `HeaderName` names the `anthropic-beta` and
`anthropic-user-profile-id` headers.
- The ID isn't validated locally. The API checks it, and a malformed or
unknown ID fails the request.
sophie-ant
force-pushed
the
sdownward/user-profiles
branch
from
September 9, 2026 17:37
f899ba8 to
428dd51
Compare
craigie-ant
approved these changes
Sep 9, 2026
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.
Summary
Lets an app attribute each request to one of its users. Set
userProfileID:onClaudeLanguageModel. Every request then sends theanthropic-user-profile-idheader, with theuser-profiles-2026-08-18beta that the header needs:Until now,
.apiKeyand.appAttestcouldn't send the header at all, and.proxiedneeded both headers set by hand. The other SDKs expose the same header as auser_profile_idrequest parameter.HeaderNamenames theanthropic-betaandanthropic-user-profile-idheaders./v1/user_profiles), which create profiles and enrollment URLs. Those belong on the developer's backend, not in an app.Rebased onto
mainafter #32 merged. It builds on that change: both add to the same executor configuration and test stub.Test plan
Live requests:
LanguageModelSessionwith a valid profile ID asuserProfileIDsucceeds, and the profile header and merged beta list reach the API as one comma-joinedanthropic-betavalue.Unit tests cover the header, the beta order, one profile header however a proxy spells it, and case-insensitive header merging.
The full test suite at f899ba8 (the same tree as 428dd51, before the rebase onto the merged #32), via
xcodebuildon macOS 26.6 with Xcode 27.0 beta 6 (27A5252f) and the iOS 27.0 simulator:** TEST SUCCEEDED **, 243 tests, 240 passed, 0 failed, 3 skipped. The 3 skips are the keychain-backedAppAttestStoreTests, which skip by design under this runner.