--- name: cursor-debug-log description: 当需要调查 Cursor 本地模式 debug/log 证据时使用:config.yaml 的 log 热加载、history//debug JSONL 文件、Bidi 原始/解码记录、RunSSE 记录、runtime/provider debug 记录、debug 文件缺失原因,或解释这些 debug 文件如何生成与如何查询。 --- # Cursor Debug Log 使用这个技能来解释和检查本地 debug log 体系。目标是在不修改已安装 Cursor 客户端、不依赖旧版 legacy artifact 的前提下,还原一次请求附近发生了什么。 ## 作用定位 debug log 是本地模式请求链路的可选证据层。它和模型可见历史是分开的: - 用来回答“客户端到底发了什么”。 - 用来回答“后端解码后认为这是什么请求”。 - 用来回答“哪些字段被挂到了当前 active request 上”。 - 用来回答“最终 provider request body 是什么样”。 - 用来回答“RunSSE 实际给客户端发送了什么”。 - 不要把它当成 replay history、prompt 输入或状态事实源。 稳定事实源仍然是: - `history//state.json` - `history//context.json` - `history/usage.json` - `logs/app.log` debug 文件是在这些事实源之外,补充原始或近原始链路证据。 ## 固定路径 - 助手根目录:`~/.cursor-local-assistant-v2` - 配置文件:`~/.cursor-local-assistant-v2/config.yaml` - history 根目录:`~/.cursor-local-assistant-v2/history` - app 日志:`~/.cursor-local-assistant-v2/logs/app.log` - 会话 debug 目录:`history//debug/` - 孤儿 debug 目录:`history/_debug/orphan//` 通过配置开启 debug logging: ```yaml log: true ``` 当前实现会用轻量文件快照检查热加载 `config.yaml`。改完 `log` 后,预留大约 500ms,再期待下一次请求事件使用新值。旧二进制可能仍然需要重启。 ## 文件如何生成 debug 层随着请求穿过后端边界逐步落盘: 1. `BidiAppend` 收到客户端上行数据。 - 原始 hex 写入 `bidi.raw.jsonl`。 - 解码后的 known-schema protobuf 与后端提取出的 intent 写入 `bidi.decoded.jsonl`。 2. forwarder 把解码结果转成 active runtime state。 - stream/request 状态决策写入 `runtime.jsonl`。 3. provider pass 被准备并执行。 - adapter 前的请求摘要、`model_call_id`、`provider_pass` 等写入 `provider.jsonl`。 - provider artifact callback 追加最终 request/summary payload 到 `provider.jsonl`。 4. `RunSSE` 把后端输出流式发送给客户端。 - 已发送消息、终态事件、发送错误、断连和 heartbeat 写入 `runsse.jsonl`。 如果某条消息到达时后端还不知道 `conversationId`,早期事件可能写到 `_debug/orphan//`。后续一旦知道 `conversationId`,新事件应进入 `history//debug/`。还原早期或乱序请求时,两处都要查。 ## Debug 文件含义 `bidi.raw.jsonl` - 方向:客户端到后端。 - 包含 `request_id`、可选 `conversation_id`、`append_seqno`、`status`、原始 `data_hex`。 - 当需要精确确认客户端上传字节时先看它。 `bidi.decoded.jsonl` - 方向:客户端到后端,protobuf 解码后。 - 当前 schema v2 包含完整的 known-schema `AgentClientMessage` protojson:`message`。 - 同时包含后端从上行包提取出的 intent:`intent`,其中会展开相关 proto 子对象,例如 `client_message`、`user_message`、`request_context`、`conversation_state`、exec/interaction/kv 回包等。 - 还包含 `message_case`、`requested_model`、`conversation_action` 等检索索引;这些索引只方便搜索,不是完整证据本体。 - 当需要确认后端如何理解客户端请求时看它。若要证明客户端原始上传字节,仍以 `bidi.raw.jsonl` 为准。 - 旧二进制或旧日志可能只有 schema v1 摘要,未必展开 `message` 和 `intent` 里的完整字段。 `runtime.jsonl` - 方向:后端内部 runtime。 - 包含状态流转,以及挂到 active stream/request 上的字段。 - 当需要把 decoded input 和后续 provider 行为串起来时看它。 `provider.jsonl` - 方向:后端到 provider adapter/provider。 - 包含 provider pass 元数据、`model_call_id`、request knobs、最终 provider request artifact、provider summary artifact。 - 当最终出站 provider body 或 provider summary 是关键证据时看它。 `runsse.jsonl` - 方向:后端到客户端。 - 包含解码后的 `AgentServerMessage` 发送、终态事件、发送错误、断连和 heartbeat。 - 用来检查后端尝试返回给客户端的内容。它是解码后的消息证据,不是原始 HTTP/SSE framing。 ## 查询流程 1. 先判断 id 类型。 - 先查 `history//state.json`,确认它是不是 `conversationId`。 - 再在 `history/*/{state.json,context.json}`、`history/usage.json`、`logs/app.log` 里搜索 request/model-call/tool id。 2. 拿到 `conversationId` 后,列出 debug 目录。 - `ls -la "$HOME/.cursor-local-assistant-v2/history//debug"` 3. 如果 debug 目录不存在,确认请求发生时 debug 是否已开启。 - 读取 `config.yaml`。 - 对比 `config.yaml`、`state.json`、`context.json` 的 mtime。 - 搜索 `logs/app.log` 里的 config hot reload 或 provider start 记录。 4. 按时间顺序读 JSONL,并用这些字段串联: - `request_id` - `conversation_id` - `model_call_id` - `provider_pass` - `append_seqno` - event timestamp 5. 最终回复只总结结论所需字段。不要粘贴 secret、API key、完整 provider body 或大段原始 payload。 常用命令: ```bash ROOT="$HOME/.cursor-local-assistant-v2" REQ="" CONV="" rg -n "$REQ" "$ROOT/history" "$ROOT/logs/app.log" find "$ROOT/history" -path "*/debug/*" -type f | sort rg -n "$REQ|model_call_id|provider_request_prepared|llm_request" "$ROOT/history/$CONV/debug" ``` 紧凑查看 JSONL: ```bash jq -c 'select(.request_id == "")' "$ROOT/history/$CONV/debug/provider.jsonl" jq -c 'select(.request_id == "") | {append_seqno, message_case, conversation_action, message, intent}' "$ROOT/history/$CONV/debug/bidi.decoded.jsonl" ``` ## 证据怎么用 根据问题选择对应文件: - 客户端原始上行问题:先看 `bidi.raw.jsonl`。这是精确原始包证据。 - 客户端 known-schema 字段问题:看 `bidi.decoded.jsonl` 的 `message`。例如 `user_message.message_id`、selected image、conversation state bytes 等字段是否在解码结果里。 - 后端如何理解请求:看 `bidi.decoded.jsonl` 的 `intent`,再接 `runtime.jsonl`。 - provider request 问题:看 `provider.jsonl`,尤其是 `llm_request`。 - UI/流式输出问题:看 `runsse.jsonl`。 - 请求状态问题:先看 `state.json`、`context.json`、`usage.json`,再用 debug 文件补证。 - debug 缺失问题:看 `config.yaml`、mtime、app log、orphan debug 目录。 runtime model parameters,例如 thinking strength,只是 provider request 证据的一类例子: - `bidi.raw.jsonl` 说明客户端原始上传了什么。 - `bidi.decoded.jsonl.message` 说明上行包按当前 known schema 解码出了什么。 - `bidi.decoded.jsonl.intent` 说明后端从 decoded input 里提取并准备使用了什么。 - `runtime.jsonl` 说明后端把什么挂到了请求状态上。 - `provider.jsonl` 说明最终为 provider 准备了什么。 只有普通 history 时不要过度断言。例如 `context.json` 里的 `reasoning_content` 能说明产生过 reasoning 文本,但不能单独证明是哪一个 runtime parameter value 导致的。 注意证据边界: - `bidi.decoded.jsonl` 使用当前已知 proto schema 做解码。未知字段或原始 framing 差异不能靠 decoded 证明,必须回到 `bidi.raw.jsonl`。 - `context.json` 仍是持久化历史事实源;debug 文件只能证明某次请求链路附近发生过什么。 - `provider.jsonl` 的 provider body 和 `bidi.raw.jsonl` / `bidi.decoded.jsonl` 都可能很大,回复用户时只摘必要字段,不粘贴完整图片、完整 body 或 secret。 ## Debug 文件缺失 如果某个 request 没有 debug 文件,要明确说明“没有直接 debug 证据”。常见原因: - 请求发生时 `log: false`。 - 正在运行的二进制版本早于 debug logging 或 hot reload 实现。 - 事件发生时还没有解析到 conversation id,记录在 `_debug/orphan//`。 - 请求在开启 `log` 前已经完成。 - 写文件失败;如果该版本有相关记录,app log 里可能有 warning。 debug 证据缺失时,回退到 `state.json`、`context.json`、`usage.json`、`logs/app.log`,并把结论标成推断,而不是直接证明。