Repository navigation
[Bug] Windows: a single unanalyzable command permanently disables shell in that session (non-POSIX working directory requires a shell path adapter) #3068
Description
Activity
补充:在会话状态文件里发现了该守卫的实现线索
后续检查本机会话状态时,在
sessions/<id>/metadata.json的customMetadata.editConstraintGuard里看到这个守卫的结构。它看起来是模型驱动的,这大概能解释为什么会"突然锁死且重启不恢复":"editConstraintGuard": { "constraints": [ { "description": "Keep the AGENTS.md entry as originally written (do not change it)", "id": "model:c5eb69895eb7:0", "matcher": { "kind": "path_contains", "substrings": ["AGENTS.md"] }, "operation_scope": "all", "source": "model" } ], "extractions": [ { "dialog_turn_id": "dialog_1789560050732_m5i0rhfcd", "extracted_at_ms": 1789560052143, "latency_ms": 1070, "model_attempts": 1, "model_status": "parsed", "status": "no_constraints", "response_excerpt": "{\"additions\": [], \"revocations\": []}" } ] }
观察到几点:
- 约束是从对话里用模型抽取出来的:用户在某一轮说"这条内容要保留原貌",被抽取成一条
path_contains: AGENTS.md的禁改约束,且source: "model"(标明由模型生成),随后用于校验工具操作。 - 校验过程带模型调用:
extractions[]中记录了latency_ms(例子中 1070 ms / 4679 ms 各一次)、model_attempts、model_status,说明每次判定可能依赖一次模型分析。 - 因此
"analysis_status": "unsupported"很可能表示模型分析环节没有跑通(超时、解析失败或返回不可用),而不是 shell 语法无法解析。这与前面的对照实验一致:同一条Get-Location交给子代理就能正常执行。 customMetadata挂在会话上,与"锁死状态跨应用重启保留、但不影响新会话与子代理"的现象完全吻合。
如果
"non-POSIX working directory requires a shell path adapter"是这条模型分析链在 Windows 路径下的兜底失败原因,那么修复方向可能是:- 分析无法完成时降级为只拒绝该条命令,而不是把整个会话的 shell 标记为不可用;
- 或者至少在 UI 明确提示该会话的 shell 已被禁用,并给出恢复/重置方式。
以上仅是从客户端状态文件观察到的线索,未必与实现一一对应,供定位参考。
- 约束是从对话里用模型抽取出来的:用户在某一轮说"这条内容要保留原貌",被抽取成一条
补充证据:约束被抽出的 9 秒后,该会话的命令即开始被拒
按上一条评论的线索继续核对会话状态,拿到了时间戳证据,因果关系基本可以坐实。
customMetadata.editConstraintGuard.extractions[]里一共只有两条记录:# 抽取时间(本地) 抽取结果 说明 1 20:00:52 status: "no_constraints"未抽到任何约束;此后约 20 分钟内多条命令( Copy-Item/python/git commit等)全部成功2 20:04:41 status: "extracted"抽出 1 条约束(用户在对话中要求某条内容保持原样) 抽出的约束内容:
{ "id": "model:c5eb69895eb7:0", "description": "Keep the AGENTS.md entry as originally written (do not change it)", "matcher": { "kind": "path_contains", "substrings": ["AGENTS.md"] }, "operation_scope": "all", "source": "model" }而同一会话首次出现守卫拒绝的时间是 20:04:50.307(
app.log第 4694 行,模块openbitfun_core::agentic::tools::pipeline::tool_pipeline,报错内容即本 issue 正文那条)。也就是说:约束被抽出后 9 秒,该会话的第一个 ExecCommand 就被拒,此后持续失效。
由此可以推出
- 会话内没有约束时:工具执行无约束可对照,命令正常放行(与本例 19:51–20:04 期间的表现一致,当时
constraints为空) - 一旦抽取到约束:此后每次工具执行都需要"对照约束做分析",而这条分析链在非 POSIX(Windows)工作目录下无法完成 →
analysis_status: "unsupported"→ 报non-POSIX working directory requires a shell path adapter - 该失败是 fail-closed,并被持久化到会话状态 → 该会话内所有 ExecCommand 被永久拒绝(跨应用重启保留)
- 新会话与子代理没有约束 → 一切正常(与上一条评论的对照实验一致)
影响定性(比"偶发锁死"更严重)
在 Windows 上,只要模型从对话中抽到任意一条约束,该会话的 shell 就基本不可用了。而"用户要求某条内容不要改动"是极常见的交互——这意味着该功能在当前 Windows 版本上从"保护机制"直接变成"瘫痪机制",并且全程没有任何用户可见提示。
建议排查方向:
- 该分析链在非 POSIX 工作目录下的路径适配:
shell path adapter由什么提供?与terminal.default_shell为空是否相关? - 分析失败时的降级策略:应只拒绝该条命令(或仅拒绝该约束覆盖的操作范围),而不是禁用整个会话的 shell
- UI 至少应告知用户"该会话已进入受限状态",并提供恢复方式
以上时间戳与字段均来自本机客户端状态文件与日志,可逐项复现核对。
- 会话内没有约束时:工具执行无约束可对照,命令正常放行(与本例 19:51–20:04 期间的表现一致,当时
该bug在win11、pwsh7上也有出现。EN TL;DR — Confirmed on 1.0.0 stable as well (not beta-only). Reproduces on pwsh 7.6.6 (Core) / Windows 11 build 26220, so it is neither shell-specific nor Win10-specific. Found a strong discriminator: the failing session is the only one whose workspace has
config/isolation_status.json(git_isolated: true) — which also explains why "new sessions and subagents work fine". One negative result too:terminal.default_shellis not the cause.
1. 复现数据
项 本例 原报告 应用版本 1.0.0-beta → 升级到 1.0.0 后仍复现(同 payload,仅 guard_decision_id不同)1.0.0 Shell pwsh 7.6.6 (PSEdition Core) Windows PowerShell 5.1.19041.6456 OS Windows 11, build 26220 Windows 10 22H2, build 19045 effective_workdir…\.openbitfun\personal_assistant\workspace(无 hash 后缀)同形状 两个 shell、两个 Windows 版本均复现 → 可排除"pwsh 特有"与"Win10 特有"两条假设。
2. 完整 guard payload
(原报告的粘贴在
force_requested处截断,此处补全){"analysis_status":"unsupported","blocks_input_rewrite":true,"constraint_id":null, "effective_workdir":"<personal_assistant workspace>", "executed":false,"failure_kind":"edit_constraint_guard","force_requested":false, "guard_decision":"deny_shell_analysis","guard_decision_id":"05766c8d-c869-427b-8e05-b963791cbb93", "operation":null,"protected_path":null, "reason":"non-POSIX working directory requires a shell path adapter", "requested_target":null,"resolved_target":null,"shell_kind":"pwsh", "source_span":{"start":0,"end":0,"end_exclusive":true,"unit":"utf8_bytes"}}字段解读,支持原报告"判定对象不是命令"的结论:
constraint_id: null→ 未命中任何具体约束,即这不是策略拒绝,而是通用兜底退出operation/requested_target/resolved_target/protected_path全为null→ 守卫未识别出操作与目标source_span为零宽(start == end == 0)→ 在产出任何定位信息之前就退出,说明"无法分析"发生在解析阶段而非约束匹配阶段- 三者合起来解释了这条消息为何对用户和模型都不可操作:拒绝时不携带任何可定位的证据
3. 定位线索:判别条件可能是
isolation_status.json,而非 shell 或 OS同一安装下存在四个会话工作区。触发 deny 的那个是唯一带
projects/<workspace>/config/isolation_status.json的:{ "created_at": "…", "git_isolated": true, "version": "1.0" }工作区 isolation_status.json目录内有 .gitExecCommand personal_assistant\workspace有( git_isolated: true)无 ❌ deny personal_assistant\workspace-<hash>无 无 ✅ 实测正常 另两个 workspace-<hash>无 无 未逐一验证 原报告环境同样有
isolation_status.json → git_isolated: true,两个独立案例同形状。据此可自洽解释"新会话正常 / 子代理正常":并非绕过了守卫,而是新会话与子代理落在没有该文件的工作区,该守卫根本未被触发。症状形似"会话被拉黑",实质更像"该工作区带隔离标记"。
推测链条(未证明,仅作定位参考):
工作区被标记
git_isolated: true,但目录内并无.git→edit_constraint_guard需经 shell 执行 git 来校验编辑是否越界 → 需按 cwd 解析路径 → Windows cwd + pwsh 缺 path adapter → 放弃解析 → fail-closed 拒绝。建议的最小验证:在带与不带该文件的两个工作区各执行同一条编辑命令,确认 deny 只在前者出现。
4. 一条负结果:
terminal.default_shell不是原因原报告怀疑该项为空相关。本机数据可排除:
- 迁移前(旧版本配置备份):
"default_shell": "" - 当前配置:
"default_shell"为非空值,且仍然复现
(该字段非空是由版本迁移过程写入的,说明正常路径下会被填上,但 deny 与之无关。)
5. 未观察到的点(避免误导)
- 未观察到跨会话扩散:同安装上另一会话(工作区无
isolation_status.json)ExecCommand 正常,与原报告"不波及新会话"一致。 - 未确认触发命令的形态,因此无法就"外部 exe + 单引号 + 花括号"这一触发特征提供正反证。
6. 期望行为追加一条(在原文 1–4 之外)
- deny 消息应携带可定位信息:至少给出命中的
constraint_id、非零宽source_span,以及"为何需要 path adapter"的具体缺失项。当前 payload 相关字段全为null+ 零宽 span,等于要求用户"修正语法"却不指出问题在哪——模型会反复重试同一条命令而耗尽会话。
感谢 @wsp1911 的快速修复,也感谢 @ManyueEureka 的复现数据。
Thanks @wsp1911 for the quick fix, and @ManyueEureka for the reproduction data.
Reacted by 秋水中的满月🌕Reacted by 秋水中的满月🌕感谢支持 OpenBitFun 🙌
Reacted by 秋水中的满月🌕Reacted by 秋水中的满月🌕
环境
D:\Openbitfun\openbitfun-desktop.exe,2026-09-15 安装)10.0.19045,AMD64)5.1.19041.6456C:\Users\admin\.openbitfun\personal_assistant\workspace现象
同一会话内,ExecCommand 起初正常可用;中途一次调用后,后续所有 ExecCommand 全部失败,报错:
此后连最无害的
Get-Location也一样被拒。复现步骤
新会话中正常执行若干命令。本例前 20 分钟内:
Test-Path、Select-String、Copy-Item、python -X utf8 xxx.py、git commit全部成功执行一条守卫无法分析的命令。本例触发命令为:
gh api repos/GCWing/OpenBitFun --jq '{full_name:.full_name, name:.name}'(特征:外部 exe + 单引号包裹 + 花括号语法)
此后再执行任意 ExecCommand(含
Get-Location)→ 全部被拒,不再恢复关键观察(对照实验)
结论:拒绝状态是会话级持久的,跨进程重启保留;不波及新会话与子代理。
为什么这不是"命令本身无法分析"
这是本 issue 最关键的一点:
Get-Location是零歧义命令,不存在"无法分析"的可能"non-POSIX working directory requires a shell path adapter"只是兜底的失败原因文案也就是说:一旦某个会话被守卫标记,它的 shell 就被整体关掉了,与该会话后续发出什么命令无关。
影响
app.json中terminal.default_shell为空是否相关?未验证)期望行为
附:定位信息
%APPDATA%\openbitfun\logs\<时间戳>\app.log,来源模块openbitfun_core::agentic::tools::pipeline::tool_pipeline~/.openbitfun/memories/)报警告Git isolation verification failed: file path is not safeapp.json→terminal.default_shell: ""、tool_permissions.policy.preset: "ask"、tool_permissions.interaction.auto_approve_ask: true;projects/<workspace>/config/isolation_status.json→git_isolated: true