feat: unify the host identity across OAuth, telemetry, and kap-server - #2382
feat: unify the host identity across OAuth, telemetry, and kap-server#2382liruifengv wants to merge 10 commits into
Conversation
X-Msh-Platform was hardcoded to kimi_code_cli in createKimiDeviceHeaders, so non-CLI hosts could not state their own platform and the desktop had to patch the header after the fact. KimiHostIdentity now carries a required platform (every host declares its own value; the CLI constant stays the fallback only for direct createKimiDeviceHeaders callers), and userAgentProduct is renamed to productName so the transport identity uses one name everywhere. All in-repo identity constructions pass platform explicitly; the wire value for CLI and VS Code hosts is unchanged (kimi_code_cli).
Replace the flat clientVersion field with a required clientIdentity (KimiHostIdentity) so every consumer reads the same host identity object: OAuthToolkitService now passes it to the OAuth toolkit, which means the OAuth device-flow endpoints (device authorization, token polling, refresh) on the kap-server path finally send the full X-Msh-* device headers instead of none, and the telemetry cloud appender reads client_version from the same source. A built-in CLI fallback keeps bare bootstrap() calls in tests working; composition roots must pass their own identity. The session export manifest grows an optional desktopVersion field (payload plumbed through; filled by kap-server in a follow-up).
The v1 managed auth facade constructed its OAuth toolkit without an identity, so token refreshes from inside the core went out without any X-Msh-* device headers. createManagedAuthFacade now takes an optional KimiHostIdentity and every call site supplies one: CoreProcessService._defaultOAuthTokenResolver forwards the core process's options.identity (the same source _defaultKimiRequestHeaders uses), and the DI-held services (oauth / auth summary / model catalog) read it from a new optional identity field on IEnvironmentService. The library-level "no identity, no device headers" contract is unchanged.
…rs from it ServerStartOptions.hostIdentity is now a required ServerHostIdentity (KimiHostIdentity + optional prompt display fields), replacing both the old optional HostIdentityOverrides (renamed to PromptIdentityOverrides, its productName field now displayName) and the version option (renamed to serverVersion — it is the engine version reported as server_version, while the host product version travels in hostIdentity.version). The server now feeds bootstrap's clientIdentity from hostIdentity and derives the default outbound headers (User-Agent + X-Msh-*) from it via createKimiDefaultHeaders, so kap-server-hosted OAuth flows and model / WebSearch requests carry the real host identity instead of a hardcoded kimi-code-cli fallback UA. Explicit header seeds still win as an escape hatch. Session export manifests record the host product version: kimiCodeVersion now carries hostIdentity.version (the engine version no longer appears), and desktop exports (desktop: true) are additionally stamped with a desktopVersion field. The instance registry keeps its host_version wire field for compatibility (kimi-inspect reads it); only the in-memory name changed to serverVersion.
kimi web now passes createKimiCodeHostIdentity(version) as the server's hostIdentity, so web-UI OAuth flows and the engine's outbound requests carry the explicit CLI identity (productName + version + platform). The explicit hostRequestHeadersSeed is dropped — kap-server derives the same headers from hostIdentity — and buildKimiDefaultHeaders goes away with its only consumer.
kimi web shares the CLI product token and platform, so its outbound requests were indistinguishable from direct CLI runs upstream. Its host identity now carries userAgentSuffix 'web', putting web-UI traffic at kimi-code-cli/<version> (web) while X-Msh-Platform stays kimi_code_cli.
🦋 Changeset detectedLatest commit: bad0bab The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
commit: |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f2a293c026
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…rap identity switch The bootstrap snapshot replaced the flat clientVersion scalar with clientIdentity, which broke klient's env() fan-out (RPCError: method not found). The wire surface keeps clientVersion — now sourced from clientIdentity.version — and bootstrapService gains a clientIdentity read (registered in envContract with an object schema) for consumers that want the full identity.
The OAuth endpoints used to receive only the X-Msh-* device headers (undici's default UA otherwise), which left the OAuth host unable to distinguish runtime surfaces — notably kimi web, whose platform matches the CLI and whose only distinguishing mark is the (web) UA suffix. The toolkit now feeds the full identity headers (User-Agent + X-Msh-*) into every device authorization, token polling, and refresh request; the request-header type widens from DeviceHeaders to OAuthRequestHeaders.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bad0bab0be
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| @@ -0,0 +1,5 @@ | |||
| --- | |||
| "@moonshot-ai/kimi-code-sdk": minor | |||
There was a problem hiding this comment.
Mark the SDK identity rename as breaking
This changeset describes a public SDK host-identity rename plus a new required platform field, and KimiHostIdentity is exported through @moonshot-ai/kimi-code-sdk, so existing callers that pass { userAgentProduct, version } will no longer compile and JS callers fail validation at runtime. Keeping this as minor will publish a breaking SDK change as backward-compatible; either preserve the old shape or get approval and record a major bump before merging.
AGENTS.md reference: AGENTS.md:L62-L62
Useful? React with 👍 / 👎.
| }): DeviceHeaders { | ||
| return { | ||
| 'X-Msh-Platform': KIMI_CODE_PLATFORM, | ||
| 'X-Msh-Platform': options.platform ?? KIMI_CODE_PLATFORM, |
There was a problem hiding this comment.
Sanitize the platform header value
When a host passes an empty/whitespace platform or a value containing invalid header characters, this path now uses it verbatim: empty strings bypass the CLI fallback and make OAuth/model requests carry a blank X-Msh-Platform, while CR/LF values make fetch reject before the request is sent. Product and version already go through the ASCII/required-header checks, so apply the same validation to platform before putting it in headers.
Useful? React with 👍 / 👎.
| /** | ||
| * Built-in identity used only when the caller omits `clientIdentity`. This is | ||
| * a fallback so bare `bootstrap()` calls in unit tests keep working — NOT the | ||
| * contract: composition roots must pass the host's own `KimiHostIdentity`. | ||
| */ |
There was a problem hiding this comment.
Move fallback comment into the file header
The new explanatory block is an inline comment next to a constant, but the scoped agent-core-v2 guidance restricts comments to the top-of-file block and explicitly disallows comments beside functions, methods, or statements. Move this rationale into the module header or remove it so the file stays consistent with the v2 comment convention.
AGENTS.md reference: packages/agent-core-v2/AGENTS.md:L13-L13
Useful? React with 👍 / 👎.
Related Issue
No linked issue — the problem is explained in the next section.
Problem
The OAuth device-flow authorization page cannot tell which client started a login flow, which blocks offering an "open the desktop app" handoff after browser authorization. Investigating that requirement exposed that the whole host-identity chain is broken in several ways:
X-Msh-Platformis hardcoded tokimi_code_cliin the oauth package — and worse, the v2OAuthToolkitService(backing kap-server, i.e.kimi weband embedded desktop servers) and the v1ServicesManagedAuthFacadeare constructed with no identity at all, so device authorization, token polling, and refresh requests go out with none of the sixX-Msh-*device headers (not even a product User-Agent). Only the CLI login path (node-sdk) sends them today.kimi-code-cli/<version>regardless of which product embeds the server.userAgentProduct,productName, flatclientVersion), no platform field in the identity type, and hosts forced to abuse DI seeds for plain configuration — the desktop replaces the whole bootstrap options object to change one version string and patches the platform header by hand after building it.What changed
One identity type, required at composition roots, derived everywhere downstream:
@moonshot-ai/kimi-code-oauth—KimiHostIdentitybecomes{ productName, version, platform, userAgentSuffix? }:userAgentProductrenamed toproductName, andplatformis a new required field so every host explicitly declares itsX-Msh-Platform(the CLI constant remains a fallback only for directcreateKimiDeviceHeaderscallers).@moonshot-ai/agent-core-v2— the bootstrap snapshot carries a requiredclientIdentity(replacing the flatclientVersion).OAuthToolkitServicepasses it to the OAuth toolkit, so the OAuth device-flow endpoints now send the fullX-Msh-*set on every host; the telemetry appender reads the client version from the same source. The session export manifest gains an optionaldesktopVersionfield.@moonshot-ai/agent-core—createManagedAuthFacadetakes an optional identity and every call site supplies one; token refreshes from inside the core now carry the device headers.@moonshot-ai/kap-server—ServerStartOptions.hostIdentityis now required (ServerHostIdentity=KimiHostIdentity+ optional prompt display fields;HostIdentityOverrideswas renamed toPromptIdentityOverrideswith itsproductNamefield nowdisplayName),versionrenamed toserverVersion(the engine version, matching theserver_versionwire field), and the default outbound headers are derived from the identity instead of a hardcoded CLI UA. Session export manifests now record the host product version askimiCodeVersion— plusdesktopVersionfor desktop exports — and no longer include the engine version.kimi webpasses the explicit CLI identity and tags its requests with a(web)User-Agent suffix so upstream can tell web-UI traffic apart from direct CLI runs;kimi -p(v2 experimental) passes the same identity.Wire-behavior notes: CLI and VS Code hosts keep reporting
kimi_code_cli(no change there). The real behavior change is that kap-server-hosted flows (kimi web, embedded desktop servers) go from sending no device headers to sending the full set, including the stableX-Msh-Device-Id— flagged here so the receiving services are not surprised.Checklist
gen-changesetsskill — 6 changesets (minor for the API breaks, patch for additive changes).gen-docsskill, or this PR needs no doc update (no user-facing docs affected).Verification
pnpm run build:packages,pnpm run typecheck,pnpm run lint— green.run-shell.test.tsreproduce identically on pristineorigin/main; kap-server'sENOTEMPTYquery-store cleanup races likewise pre-date this change).hostIdentityissuesPOST /api/oauth/device_authorizationcarrying all sixX-Msh-*headers with the desktop platform value.