feat(settings): 支持全局与项目提示词配置 - #587
Conversation
…scopes-271 # Conflicts: # crates/agent-gui/src/pages/chat/runtime/useSendChatTurn.ts
su-fen
left a comment
There was a problem hiding this comment.
审核结论
建议先修再合。CI 已绿、也能自动合并,分层模型和空闲直发路径是对的,但 Text 模式排队发送会把这次要修的问题重新引进来。
必须修
[P2] 空的 workdirOverride 被当成会话工作区
resolveConversationPromptWorkdir 只要看到 workdirOverride !== undefined 就直接返回,包括空串。排队链路在 Text 模式下会把 workdir 写成 "",再作为 workdirOverride 传进发送函数。
结果是「上一条还在跑、用户接着发下一条」时:
- 项目提示词失效,只剩全局模板
historyCwd变成undefined,会话cwd被写成NULL,对话从项目里拆出去- 运行时
workdir被清掉,后面几轮也解析不到项目提示词
这正好打到 PR 自己写的目标:Text 模式要单独解析 conversation workspace,避免工具工作目录为空时退回全局提示词。空闲直发没有 override,所以能过;一进队列,空的工具工作目录又漏回提示词解析。覆盖策略为 replace 时更明显。
建议二选一:
- 空覆盖视为未指定,回落到
persistedWorkdir/runtimeWorkdir - 排队时 Text 模式不要传
workdirOverride
不要把项目路径写进 Text 模式的 workdirOverride,否则工具层会错误拿到工作目录。现有测试只覆盖了「没有 override」,请补一条 workdirOverride: "" 且会话已有 cwd 的用例。
其余看起来没问题
resolveEffectivePromptSettings的 append / replace / 空项目回退全局,语义清楚,也有单测- 项目提示词挂在现有
workspaceResourceSettings上,更新时保留 Skill / MCP;inherit 墓碑和溢出淘汰也把「仅有项目提示词」的条目算成活跃 - 普通发送、Cron、当前会话手动压缩都走同一套解析
- 设置页和项目配置弹窗的入口与文案一致
残留说明(不挡这次,但建议知道)
| if (explicitWorkdir !== undefined) { | ||
| return explicitWorkdir.trim(); | ||
| } | ||
| if (!params.isAgentMode) { | ||
| return ""; | ||
| } | ||
| return ( |
There was a problem hiding this comment.
[P2] 空字符串 override 不应覆盖会话工作区
排队链路在 Text 模式会把 workdir 写成 "",再作为 workdirOverride 传入。这里 explicitWorkdir !== undefined 对空串也成立,于是直接返回 "",丢掉 persistedWorkdir / runtimeWorkdir。
空闲直发没有 override,项目提示词能生效;一旦上一条还在跑、用户接着发下一条,就会:
- 项目提示词失效,只剩全局模板
historyCwd变成undefined,把会话cwd写空- 运行时
workdir被清掉,后续轮次也解析不到项目提示词
这和本 PR「Text 模式单独解析 conversation workspace」的目标相反。空覆盖应视为未指定并回落到会话 cwd;不要把项目路径写进 Text 模式的 workdirOverride,否则工具层会错误拿到工作目录。请补一条 workdirOverride: "" 且会话已有 cwd 的测试。
| const workdirResolution = { | ||
| isAgentMode: effectiveIsAgentMode, | ||
| workdirOverride: overrides?.workdirOverride, | ||
| gatewayWorkdirOverride: gatewayBridgeRequest?.workdirOverride, | ||
| persistedWorkdir: sidebarStore.peek(conversationId)?.cwd, | ||
| runtimeWorkdir: runtimeEntry?.workdir, | ||
| globalWorkdir: settings.system.workdir, | ||
| }); | ||
| }; | ||
| const effectiveWorkdir = resolveEffectiveConversationWorkdir(workdirResolution); | ||
| const promptWorkdir = resolveConversationPromptWorkdir(workdirResolution); | ||
| const effectiveAgentPrompt = resolveEffectivePromptSettings(settings, promptWorkdir).prompt; |
There was a problem hiding this comment.
这里把同一份 workdirResolution 同时交给工具工作目录和提示词工作目录。队列传入的 Text 模式 workdirOverride: "" 会让 promptWorkdir 变成空串,随后 historyCwd 也被写成 undefined。
resolveEffectiveConversationWorkdir 在 Text 模式返回空是对的(工具不该有工作目录);resolveConversationPromptWorkdir 不应把这个空覆盖当成「会话不属于任何项目」。
概述
为提示词配置增加清晰的全局与项目两层作用域,同时保留现有全局模板单选互斥行为。
主要改动
设计取舍
Issue 最初建议同时启用多个全局模板。本实现没有改变现有全局单选模型,而是通过“一个全局模板 + 一份项目提示词”的分层方式提供组合能力,降低全局模板顺序和冲突管理的复杂度。
界面预览
验证
pnpm -w run check:fast:12/12 通过Closes #271