makecindy / makecindy/cindy

长会话网关返回损坏的 HTTP 200,且手机端前置说明导致 /compact 失效

Open
#2,242 1 comment 0 reactions 0 assignees View on GitHub
bug
Dominant language
TypeScript
Stars
2.7k
Forks
395
Avg merge
21h 48m
Merged PRs (30d)
776

Description

**提交人**: jermy
**客户端版本**: 0.1.37

---

## 现象

在 Cindy 桌面通过 Claude Code runtime 使用主机管理的模型路由时,一个长会话在约 37 万 tokens(模型标称 1M 上下文)后突然无法继续。后续每次发送消息都得到:

```text
API Error: API returned an empty or malformed response (HTTP 200) — check for a proxy or gateway intercepting the request
```

同一模型在新建会话中可以正常回复,因此不是账号、网络或模型整体不可用。Claude Code 的请求经过 Cindy 本地网关;旧会话没有出现自动压缩记录,且当时距离 1M 上限仍较远。

此外,从手机客户端向该旧会话发送 `/compact` 时,客户端自动在命令前加入“客户端说明”。最终送入 Claude Code 的消息结构类似:

```text
[客户端说明] ...
/compact
```

因此 `/compact` 不再位于消息开头,被当作普通用户消息发送给模型,没有触发 Claude Code 本地压缩命令,随后继续撞上同一个网关空响应。

## 复现步骤

### 问题一:长会话网关响应损坏

1. 在 Cindy 中创建 Claude Code 会话,使用支持 1M 上下文的主机管理模型路由。
2. 进行较长、包含多轮工具调用和文件操作的对话,使有效上下文增长到约 37 万 tokens。
3. 正常发送下一条用户消息。
4. 观察 Claude Code transcript:网关返回 HTTP 200,但响应体为空或不符合预期的流式协议。
5. 重试或继续发送消息,错误稳定复现;新建同模型会话则正常。

### 问题二:手机端破坏斜杠命令

1. 从 Cindy 手机端打开一个 Claude Code 会话。
2. 发送 `/compact`。
3. 检查 Claude Code transcript。
4. 可以看到系统自动追加的客户端说明位于 `/compact` 之前,导致命令未被识别。

## 期望行为

1. Cindy 本地模型网关应返回 Claude Code 可解析的标准流式响应;如果上游失败,应返回明确、可分类、可重试的错误码和错误体,不能以 HTTP 200 返回空或损坏内容。
2. 对长会话请求,如果上游或网关存在大小限制,应在到达限制前触发可恢复的压缩、给出明确限制信息,或提供自动迁移/恢复机制,不能让会话永久无法继续。
3. 手机端发送 Claude Code 斜杠命令时,命令必须原样透传,或把客户端说明放入独立的系统上下文,不能在命令正文前插入文本。
4. `/compact` 应在手机端与桌面端保持一致,能够触发 Claude Code 的本地压缩流程。

## 实际行为

1. 网关连续返回格式损坏的 HTTP 200,Claude Code只能记录 synthetic API error,旧会话无法继续。
2. 切换到 256K 模型会明确提示上下文超过 256K,但切回原 1M 模型仍收到损坏的 HTTP 200。
3. 手机端 `/compact` 被前置说明文本破坏,变成普通模型请求,无法用于恢复旧会话。
4. 用户只能新建会话并人工迁移上下文,原会话无法自愈。
---
**OS**: darwin arm64 (25.5.0)
**界面语言**: zh-CN

Contributor guide

Open the contributing guide

Research direction

Start by tracing Cindy’s local model gateway and the mobile message-construction path, then compare their handling of Claude Code transcripts and slash commands. Reproduce both failures with a long session and a mobile `/compact` request. Done means the gateway returns parseable responses or explicit errors, and `/compact` reaches Claude Code unchanged and triggers its normal compression flow.

Written by the indexing model from the issue text.

Assessment

Tech stack
electron, react-native, typescript
Domain
api, backend, mobile
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.