diff --git a/CHANGELOG.md b/CHANGELOG.md index 169cb6093..b68a9e1d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Only write entries that are worth mentioning to users. ## Unreleased +- Core: Fix HTTP header values containing trailing whitespace/newlines on certain Linux systems (e.g. kernel 6.8.0-101) causing connection errors — strip whitespace from ASCII header values before sending - Core: Fix OpenAI Responses provider sending implicit `reasoning.effort=null` which breaks Responses-compatible endpoints that require reasoning — reasoning parameters are now omitted unless explicitly set - Core: Fix context compaction failing when conversation contains media parts (images, audio, video) — switch from blacklist filtering (exclude `ThinkPart`) to whitelist filtering (only keep `TextPart`) to prevent unsupported content types from being sent to the compaction API - Web: Fix `@` file mention index not refreshing after switching sessions or when workspace files change — reset index on session switch, auto-refresh after 30s staleness, and support path-prefix search beyond the 500-file limit diff --git a/docs/en/release-notes/changelog.md b/docs/en/release-notes/changelog.md index 361a6609e..0fb7aa999 100644 --- a/docs/en/release-notes/changelog.md +++ b/docs/en/release-notes/changelog.md @@ -4,6 +4,7 @@ This page documents the changes in each Kimi Code CLI release. ## Unreleased +- Core: Fix HTTP header values containing trailing whitespace/newlines on certain Linux systems (e.g. kernel 6.8.0-101) causing connection errors — strip whitespace from ASCII header values before sending - Core: Fix OpenAI Responses provider sending implicit `reasoning.effort=null` which breaks Responses-compatible endpoints that require reasoning — reasoning parameters are now omitted unless explicitly set - Core: Fix context compaction failing when conversation contains media parts (images, audio, video) — switch from blacklist filtering (exclude `ThinkPart`) to whitelist filtering (only keep `TextPart`) to prevent unsupported content types from being sent to the compaction API - Web: Fix `@` file mention index not refreshing after switching sessions or when workspace files change — reset index on session switch, auto-refresh after 30s staleness, and support path-prefix search beyond the 500-file limit diff --git a/docs/zh/release-notes/changelog.md b/docs/zh/release-notes/changelog.md index 040492456..586b01995 100644 --- a/docs/zh/release-notes/changelog.md +++ b/docs/zh/release-notes/changelog.md @@ -4,6 +4,7 @@ ## 未发布 +- Core:修复部分 Linux 系统(如内核版本 6.8.0-101)上 HTTP 请求头包含尾部空白/换行符导致连接错误的问题——发送前对 ASCII 请求头值执行空白裁剪 - Core:修复 OpenAI Responses provider 隐式发送 `reasoning.effort=null` 导致需要推理的 Responses 兼容端点报错的问题——现在仅在显式设置时才发送推理参数 - Core:修复对话包含媒体内容(图片、音频、视频)时上下文压缩失败的问题——将过滤策略从黑名单(排除 `ThinkPart`)改为白名单(仅保留 `TextPart`),防止不支持的内容类型被发送到压缩 API - Web:修复 `@` 文件提及索引在切换会话或工作区文件变更后不刷新的问题——切换会话时重置索引,30 秒过期自动刷新,输入路径前缀可查找超出 500 文件上限的文件 diff --git a/src/kimi_cli/auth/oauth.py b/src/kimi_cli/auth/oauth.py index 96d025d96..801fee3e4 100644 --- a/src/kimi_cli/auth/oauth.py +++ b/src/kimi_cli/auth/oauth.py @@ -195,7 +195,7 @@ def get_device_id() -> str: def _ascii_header_value(value: str, *, fallback: str = "unknown") -> str: try: value.encode("ascii") - return value + return value.strip() except UnicodeEncodeError: sanitized = value.encode("ascii", errors="ignore").decode("ascii").strip() return sanitized or fallback diff --git a/tests/auth/test_ascii_header.py b/tests/auth/test_ascii_header.py new file mode 100644 index 000000000..0deb1e6c8 --- /dev/null +++ b/tests/auth/test_ascii_header.py @@ -0,0 +1,42 @@ +"""Tests for _ascii_header_value and _common_headers in oauth module. + +Regression tests for the issue where Linux kernel version strings containing +trailing whitespace/newlines (e.g. platform.version() returning +"#101-Ubuntu SMP ...\n") would be included in HTTP headers, causing +connection errors. +""" + +from unittest.mock import patch + +from kimi_cli.auth.oauth import _ascii_header_value, _common_headers + + +class TestAsciiHeaderValue: + """Test cases for _ascii_header_value.""" + + def test_plain_ascii(self) -> None: + assert _ascii_header_value("hello") == "hello" + + def test_strips_trailing_newline(self) -> None: + """Regression: Linux platform.version() may contain trailing newline.""" + assert _ascii_header_value("6.8.0-101\n") == "6.8.0-101" + + def test_non_ascii_sanitized(self) -> None: + assert _ascii_header_value("héllo") == "hllo" + + def test_all_non_ascii_returns_fallback(self) -> None: + assert _ascii_header_value("你好") == "unknown" + + +class TestCommonHeaders: + """Test that _common_headers returns clean header values.""" + + @patch("kimi_cli.auth.oauth.platform") + @patch("kimi_cli.auth.oauth.get_device_id", return_value="abc123") + def test_no_whitespace_in_header_values(self, _mock_device_id, mock_platform) -> None: + """All header values must be free of leading/trailing whitespace.""" + mock_platform.node.return_value = "myhost" + mock_platform.version.return_value = "#101-Ubuntu SMP\n" + headers = _common_headers() + for key, value in headers.items(): + assert value == value.strip(), f"Header {key!r} has untrimmed whitespace: {value!r}"