Skip to content
This repository was archived by the owner on Sep 23, 2026. It is now read-only.
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 37 additions & 19 deletions src/kimi_cli/acp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,26 +74,35 @@ async def initialize(
terminal_args = args + ["login"]

# Build and cache auth methods for reuse in AUTH_REQUIRED errors
self._auth_methods = [
acp.schema.AuthMethod(
id="login",
name="Login with Kimi account",
description=(
"Run `kimi login` command in the terminal, "
"then follow the instructions to finish login."
# Skip login method if user already has API-key based auth configured
config = load_config()
has_api_key = any(
provider.api_key and provider.api_key.get_secret_value()
for provider in config.providers.values()
)
if has_api_key or self._check_token_usable() is None:
self._auth_methods = []
Comment on lines +83 to +84

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep login method cached for future auth failures

Avoid clearing self._auth_methods in initialize when auth currently looks usable. _check_auth() later builds its AUTH_REQUIRED payload from this cached list, so if the token expires (or API-key config is removed) after initialization, the server will return AUTH_REQUIRED with an empty authMethods array and clients lose the terminal login action (kimi login) needed to recover.

Useful? React with 👍 / 👎.

Comment on lines +83 to +84

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 AUTH_REQUIRED error raised with empty authMethods when token expires mid-session

When the OAuth token is valid at initialize time, self._auth_methods is set to [] (line 84). If the token later expires (no refresh token) and the user has no API key, _check_auth (line 137) falls through to building auth_methods_data from self._auth_methods which is [], and raises auth_required({"authMethods": []}) at line 166. The client receives an AUTH_REQUIRED error but with no auth methods to present to the user, leaving them stuck with no way to re-authenticate. Before this PR, self._auth_methods was always populated with the login method, so the client always received actionable auth instructions.

Prompt for agents
The problem is that `self._auth_methods` is conditionally cleared in `initialize()` based on point-in-time auth state, but `_check_auth()` later depends on `self._auth_methods` to construct a useful AUTH_REQUIRED error. When the token was valid at init but expires later (with no refresh token and no API key), the AUTH_REQUIRED error is raised with an empty authMethods list.

Two possible approaches:
1. Always populate `self._auth_methods` with the login method (as it was before), but only include it in the `InitializeResponse.auth_methods` conditionally. This way the cached data is always available for `_check_auth` error construction.
2. In `_check_auth`, construct the auth methods on-the-fly (using the same terminal-auth data) rather than relying on the cached `self._auth_methods` list.

Approach 1 is the simplest — decouple what's advertised in the InitializeResponse from what's used internally for error reporting. The relevant code is in `src/kimi_cli/acp/server.py`, specifically the `initialize` method (lines 76-105) and `_check_auth` method (lines 137-166).
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +83 to +84

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve login method for later AUTH_REQUIRED responses

initialize() clears self._auth_methods whenever the OAuth token is usable, but _check_auth() later derives the AUTH_REQUIRED payload from this cached list. If a long-lived ACP server starts while the token is valid and the token later expires without a refresh token, new_session/load_session will raise auth_required with an empty authMethods list, so clients lose the terminal-login metadata needed to guide re-authentication.

Useful? React with 👍 / 👎.

else:
self._auth_methods = [
acp.schema.AuthMethod(
id="login",
name="Login with Kimi account",
description=(
"Run `kimi login` command in the terminal, "
"then follow the instructions to finish login."
),
# Store auth data in field_meta for building AUTH_REQUIRED error
field_meta={
"terminal-auth": {
"command": command,
"args": terminal_args,
"label": "Kimi Code Login",
"env": {},
"type": "terminal",
}
},
),
# Store auth data in field_meta for building AUTH_REQUIRED error
field_meta={
"terminal-auth": {
"command": command,
"args": terminal_args,
"label": "Kimi Code Login",
"env": {},
"type": "terminal",
}
},
),
]
]

return acp.InitializeResponse(
protocol_version=self.negotiated_version.protocol_version,
Expand Down Expand Up @@ -129,6 +138,15 @@ def _check_auth(self) -> None:
"""Check if Kimi Code authentication is complete. Raise AUTH_REQUIRED if not."""
reason = self._check_token_usable()
if reason:
# Allow API-key based authentication as an alternative to OAuth
config = load_config()
has_api_key = any(
provider.api_key and provider.api_key.get_secret_value()
for provider in config.providers.values()
Comment on lines +143 to +145

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict API-key bypass to active/default provider

_check_auth() currently treats the presence of any provider API key as authenticated, regardless of which provider the session will actually use. In multi-provider configs, an unrelated API key can bypass auth even when the default model is on an OAuth provider with no usable token, causing session creation to pass and then fail at prompt time with 401/internal errors instead of returning a clear AUTH_REQUIRED flow.

Useful? React with 👍 / 👎.

)
if has_api_key:
return

auth_methods_data: list[dict[str, Any]] = []
for m in self._auth_methods:
if m.field_meta and "terminal-auth" in m.field_meta:
Expand Down
Loading