You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
src/launcher.ts:1400-1410 注释原文即此机制:"every non-api.openai.com base URL defaults to "short", which sends NO key and leaves the request anonymous (the proxy then 400s, 会话身份不稳定:credential/upstream 维度导致长会话状态孤儿化(sessions 缺失) #286)" —— 与 owner 的源码级分析逐字一致。
Activity
ranxianglei commentedon Aug 27, 2026
[bot] 已在代码层面核实根因,与你的诊断一致,并有一处版本修正。
根因确认
#286(commit
2b48762)把会话身份从「内容指纹兜底」改成「无客户端会话标识即硬 400」:src/server.ts:816-823:if (!clientProvided)→writeHead(400)+ 拒绝转发,日志refusing to create a content-fingerprint session (#286)src/server.ts:113-115:NO_IDENTITY_MESSAGEdsh web 不发
x-session-id/x-acp-session等头,body 也无session_id/prompt_cache_key→ 落到内容指纹 →clientProvided=false→ 400。诊断正确。版本修正(重要)
回归点实际是 0.1.58,不是 0.1.59:
v0.1.57protocol|upstream|apiKey|conversation隔离v0.1.58v0.1.59git diff 662781b dce16e6 -- src/server.ts该区域为空)你日志里「400 仅自 0.1.59 起出现」应是 0.1.58 那 10 分钟窗口(15:34→15:44)没测 dsh 所致。你降级到 0.1.57 的缓解是对的——0.1.57 是最后一个好版本。
#286 的意图 vs 过度
#286 想消除内容指纹会话的两个隐患:
apiKey/upstream,凭证轮换/换 relay 时状态瞬间孤儿化。所以选择「匿名请求显式失败」而非静默建会话。但改法过度了:它把「无会话头的第三方 harness」整类客户端一起 400,而这类客户端自身无压缩、完全依赖 bili,400 即整条链路瘫痪——比它想消除的「静默孤儿」严重得多(孤儿最坏只是丢一段压缩状态、客户端重放全量历史,等于新会话)。
权衡
--passthrough可选解法(待你裁定)
--allow-anonymous-sessions/BILI_ALLOW_FINGERPRINT_SESSIONS/ configallowFingerprintSessions)——默认保持 400(会话身份不稳定:credential/upstream 维度导致长会话状态孤儿化(sessions 缺失) #286 语义不变),有第三方 harness 的用户显式开启。最保守。我倾向 方案 2(opt-in):保住 #286 的默认安全语义,又给 dsh web 这类无会话头 harness 一条不牺牲压缩的活路;配置项可灰度,不强制所有用户承受指纹碰撞面。
确认方向后我来实现 + 补测试 + 走 release 流程。
ranxianglei commentedon Aug 28, 2026
你应该先确认为啥 dsh 配置 127.0.0.1 bili 代理为啥没有识别到本来就有的 sessions id bili dsh 应该能识别的
ranxianglei commentedon Aug 28, 2026
Model: glm-5.3
实证回答 owner 的问题:为什么 dsh 的 session id 没被识别
结论:dsh 的 session id 不是「本来就在线上」的——它只在特定条件下才发送,而报告者的配置方式恰好绕过了那个条件。
dsh 侧机制(源码级)
dsh 内置的 pi-ai 栈(
@earendil-works/pi-ai/dist/api/openai-completions.js:519-522):cacheRetention的解析顺序(同文件 :94-100):profile 显式配置 >PI_CACHE_RETENTION环境变量 > 默认"short"。关键:非 api.openai.com 的 baseURL(包括指向 bili 的 127.0.0.1)默认是
"short"→ 不发送 prompt_cache_key → 请求匿名。dsh CLI 本身从不发送 x-session-id 等任何会话头。bili 侧机制
bili dshlauncher(src/launcher.ts:1406)正是为此注入env.PI_CACHE_RETENTION = "long"——这让 pi-ai 给每个请求带上prompt_cache_key = dsh 会话 uuid,代理据此建会话。同时 launcher 还做DEEPSEEK_BASE_URL包裹 +~/.dsh-bilioverlay 重写 settings.yaml——用户根本不需要手动把 baseURL 指向 bili。本机实证(dsh 0.1.1-rc.2 + bili 0.1.59,与报告者同版本)
refusing to create a content-fingerprint session (#286),与 issue 现象逐字一致PI_CACHE_RETENTION=longtools=[compress,decompress,search_context,acp_status]注入、processTurn/nudge 正常,零 400定性
dsh web),身份注入(PI_CACHE_RETENTION)、overlay 重写、上游包裹全部没发生。dsh web是 profile boot(同进程),bili dsh web的 env 注入对 web 形态同样生效。建议
bili dsh web启动(而非手动改 settings.yaml + 直接dsh web),并把 settings.yaml 的 baseURL 恢复为真实上游——launcher 会自动做包裹与重写。另外手动配置若坚持使用,baseURL 应为http://127.0.0.1:8787/bili/<真实上游>前缀形式(裸指向 127.0.0.1:8787 会转发到默认上游 api.anthropic.com——我测试 A 中实测到的次要坑)。allowFingerprintSessions)仍然值得做:给确实无法走 launcher 的第三方 harness 一条不牺牲压缩的活路,默认语义保持 会话身份不稳定:credential/upstream 维度导致长会话状态孤儿化(sessions 缺失) #286。方案 1(直接修回)和方案 3(折中)次之。ranxianglei commentedon Aug 28, 2026
[bot] 已逐条核实 owner 的实证结论,代码层面全部吻合:
src/launcher.ts:1411:env.PI_CACHE_RETENTION = "long"—— dsh launcher 正是为此注入,让 pi-ai 每个请求带prompt_cache_key = dsh 会话 uuid。src/launcher.ts:1400-1410注释原文即此机制:"every non-api.openai.com base URL defaults to "short", which sends NO key and leaves the request anonymous (the proxy then 400s, 会话身份不稳定:credential/upstream 维度导致长会话状态孤儿化(sessions 缺失) #286)" —— 与 owner 的源码级分析逐字一致。dsh web,绕过了 launcher 的PI_CACHE_RETENTION注入 / overlay 重写 / 上游包裹,所以请求匿名 → 400。定性确认:回归成立,但根因是「手动配置路径从来没有身份注入」,不是 launcher 路径退化。owner 的 A/B 对照(A 复现 400、B 加
PI_CACHE_RETENTION=long后零 400 + tools 注入)是决定性证据。按 owner 裁定,实施方案 2(opt-in),设计如下:
--allow-fingerprint-sessions/--no-allow-fingerprint-sessions+ envBILI_ALLOW_FINGERPRINT_SESSIONS+ config 文件allowFingerprintSessions: boolean。protocol|upstream|apiKey|conversation)隔离碰撞(不同账号/上游不串状态),并打 warn 日志标记「匿名指纹会话」让孤儿化可见。session_id/prompt_cache_key)始终优先;opt-in 只影响「完全匿名」的请求。我现在实现 + 补测试 + 跑 typecheck/test/build,然后开 PR(base master)。版本 bump 走独立 release 流程,由你 merge 后 CI 发布。owner 建议 3(文档补「第三方 harness 手动接入」一节)我会在同一 PR 一并补上。
ranxianglei commentedon Aug 28, 2026
[bot] 方案 2(opt-in)已实现并开 PR:#310 (base master,待你 merge;版本 bump 走独立 release 流程,merge 后 CI 自动发布)。
改动
新增
allowFingerprintSessions(默认false,#286 语义对现有用户零改动)。开启后,无客户端会话标识的匿名请求回退到内容指纹会话,用 #286 前的 4 维隔离 key:不同账号/上游不串压缩状态;匿名会话打 warn 日志 + web UI 标
[fingerprint],让孤儿化可见。客户端提供的真实标识(header / bodysession_id/prompt_cache_key)始终优先。配置面:CLI
--allow-fingerprint-sessions/--no-allow-fingerprint-sessions· envBILI_ALLOW_FINGERPRINT_SESSIONS=1· config"allowFingerprintSessions": true。文件:
src/session-id.ts(新增deriveFingerprintSessionId,SHA-256 单向哈希,凭证不进明文)、src/config.ts、src/cli.ts、src/server.ts(!clientProvided块改为按开关回退而非无条件 400)、tests/e2e-session-identity.test.ts(1 单测 + 5 e2e:匿名→200+建会话、连续性、凭证隔离、内容隔离、客户端标识优先)、README.md/CONFIGURATION.md(新增「第三方 harness 手动接入」一节 + 配置/env/flag 参考行)。Pre-flight:
typecheck干净 ·test704 通过 / 0 失败 ·build成功。无依赖变更(package-lock.json未动)。给报告者的即时缓解(等 PR 落地前)
按 owner 的实证结论,最干净的是改用
bili dsh web启动(launcher 注入PI_CACHE_RETENTION=long→prompt_cache_key= dsh 会话 uuid,并自动做上游包裹/重写),把 settings.yaml 的 baseURL 恢复为真实上游。若坚持手动配置,0.1.58/0.1.59 上可先降级 0.1.57(最后一个带指纹兜底的版本)。本 PR 落地后,手动配置路径加--allow-fingerprint-sessions即可恢复压缩而无需 launcher。Merge pull request #311 from ranxianglei/2026-08-28_anonymous-prefix-…
refactor: drop the dead SSE rewriters that kept causing mis-triage
fix: exclude anonymous pfa sessions from legacy-id migration (#499 pr…
feat: anonymous prefix-affinity session resolution (ranxianglei#309)
docs: rewrite 'How sessions work' — verbatim client id + prefix affin…
fix: stop leaking prompt_cache_key into anthropic upstreams (ranxiang…
feat: inherit refs/blocks/lineage across resume forks (#1486)
feat: opt-in content-fingerprint sessions for header-less clients (ra…