feat: add silent disable option and workspace prompt split
This commit is contained in:
parent
50b0dd9336
commit
55ef45e04d
@ -145,6 +145,7 @@ class MainTerminal:
|
|||||||
)
|
)
|
||||||
self.easter_egg_manager = EasterEggManager()
|
self.easter_egg_manager = EasterEggManager()
|
||||||
self._announced_sub_agent_tasks = set()
|
self._announced_sub_agent_tasks = set()
|
||||||
|
self.silent_tool_disable = False # 是否静默工具禁用提示
|
||||||
self.current_session_id = 0 # 用于标识不同的任务会话
|
self.current_session_id = 0 # 用于标识不同的任务会话
|
||||||
# 工具类别(可被管理员动态覆盖)
|
# 工具类别(可被管理员动态覆盖)
|
||||||
self.tool_categories_map = dict(TOOL_CATEGORIES)
|
self.tool_categories_map = dict(TOOL_CATEGORIES)
|
||||||
@ -428,6 +429,9 @@ class MainTerminal:
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
logger.warning("忽略无效默认运行模式: %s", preferred_mode)
|
logger.warning("忽略无效默认运行模式: %s", preferred_mode)
|
||||||
|
|
||||||
|
# 静默禁用工具提示
|
||||||
|
self.silent_tool_disable = bool(effective_config.get("silent_tool_disable"))
|
||||||
|
|
||||||
|
|
||||||
def _handle_read_tool(self, arguments: Dict) -> Dict:
|
def _handle_read_tool(self, arguments: Dict) -> Dict:
|
||||||
"""集中处理 read_file 工具的三种模式。"""
|
"""集中处理 read_file 工具的三种模式。"""
|
||||||
@ -664,6 +668,8 @@ class MainTerminal:
|
|||||||
|
|
||||||
def _format_disabled_tool_notice(self) -> Optional[str]:
|
def _format_disabled_tool_notice(self) -> Optional[str]:
|
||||||
"""生成禁用工具提示信息 / Format disabled tool notice."""
|
"""生成禁用工具提示信息 / Format disabled tool notice."""
|
||||||
|
if getattr(self, "silent_tool_disable", False):
|
||||||
|
return None
|
||||||
if not self.disabled_notice_tools:
|
if not self.disabled_notice_tools:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -2508,6 +2514,10 @@ class MainTerminal:
|
|||||||
{"role": "system", "content": system_prompt}
|
{"role": "system", "content": system_prompt}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
workspace_system = self.context_manager._build_workspace_system_message(context)
|
||||||
|
if workspace_system:
|
||||||
|
messages.append({"role": "system", "content": workspace_system})
|
||||||
|
|
||||||
if self.tool_category_states.get("todo", True):
|
if self.tool_category_states.get("todo", True):
|
||||||
todo_prompt = self.load_prompt("todo_guidelines").strip()
|
todo_prompt = self.load_prompt("todo_guidelines").strip()
|
||||||
if todo_prompt:
|
if todo_prompt:
|
||||||
|
|||||||
@ -38,6 +38,7 @@ DEFAULT_PERSONALIZATION_CONFIG: Dict[str, Any] = {
|
|||||||
"tool_intent_enabled": True,
|
"tool_intent_enabled": True,
|
||||||
"default_model": "kimi-k2.5",
|
"default_model": "kimi-k2.5",
|
||||||
"image_compression": "original", # original / 1080p / 720p / 540p
|
"image_compression": "original", # original / 1080p / 720p / 540p
|
||||||
|
"silent_tool_disable": False, # 禁用工具时不向模型插入提示
|
||||||
}
|
}
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
@ -164,6 +165,12 @@ def sanitize_personalization_payload(
|
|||||||
elif base.get("image_compression") not in allowed_image_modes:
|
elif base.get("image_compression") not in allowed_image_modes:
|
||||||
base["image_compression"] = "original"
|
base["image_compression"] = "original"
|
||||||
|
|
||||||
|
# 静默禁用工具提示
|
||||||
|
if "silent_tool_disable" in data:
|
||||||
|
base["silent_tool_disable"] = bool(data.get("silent_tool_disable"))
|
||||||
|
else:
|
||||||
|
base["silent_tool_disable"] = bool(base.get("silent_tool_disable"))
|
||||||
|
|
||||||
return base
|
return base
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -136,22 +136,7 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. 工作区信息
|
## 7. 核心原则
|
||||||
|
|
||||||
- **运行环境**:隔离容器中(挂载目录 {container_path}),宿主机路径已隐藏
|
|
||||||
- **资源限制**:CPU {container_cpus} 核,内存 {container_memory},磁盘配额 {project_storage}
|
|
||||||
- **当前时间**:{current_time}
|
|
||||||
- **项目结构**:
|
|
||||||
|
|
||||||
```
|
|
||||||
{file_tree}
|
|
||||||
```
|
|
||||||
|
|
||||||
- **长期记忆**:{memory}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. 核心原则
|
|
||||||
|
|
||||||
1. **安全第一**:只操作授权范围内的文件
|
1. **安全第一**:只操作授权范围内的文件
|
||||||
2. **沟通为主**:不确定时多问,不要自作主张
|
2. **沟通为主**:不确定时多问,不要自作主张
|
||||||
@ -159,8 +144,6 @@
|
|||||||
4. **用户友好**:用简单的语言解释复杂的操作
|
4. **用户友好**:用简单的语言解释复杂的操作
|
||||||
5. **正确执行**:主动确认细节,获得明确许可后再开始
|
5. **正确执行**:主动确认细节,获得明确许可后再开始
|
||||||
|
|
||||||
---
|
## 8. 个性化配置
|
||||||
|
|
||||||
## 9. 个性化配置
|
|
||||||
|
|
||||||
当用户的个性化信息与上文冲突时,以用户的个性化信息为准。
|
当用户的个性化信息与上文冲突时,以用户的个性化信息为准。
|
||||||
|
|||||||
@ -154,22 +154,7 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. 工作区信息
|
## 7. 核心原则
|
||||||
|
|
||||||
- **运行环境**:隔离容器中(挂载目录 {container_path}),宿主机路径已隐藏
|
|
||||||
- **资源限制**:CPU {container_cpus} 核,内存 {container_memory},磁盘配额 {project_storage}
|
|
||||||
- **当前时间**:{current_time}
|
|
||||||
- **项目结构**:
|
|
||||||
|
|
||||||
```
|
|
||||||
{file_tree}
|
|
||||||
```
|
|
||||||
|
|
||||||
- **长期记忆**:{memory}
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 8. 核心原则
|
|
||||||
|
|
||||||
1. **安全第一**:只操作授权范围内的文件
|
1. **安全第一**:只操作授权范围内的文件
|
||||||
2. **沟通为主**:不确定时多问,不要自作主张
|
2. **沟通为主**:不确定时多问,不要自作主张
|
||||||
@ -177,8 +162,6 @@
|
|||||||
4. **用户友好**:用简单的语言解释复杂的操作
|
4. **用户友好**:用简单的语言解释复杂的操作
|
||||||
5. **正确执行**:主动确认细节,获得明确许可后再开始
|
5. **正确执行**:主动确认细节,获得明确许可后再开始
|
||||||
|
|
||||||
---
|
## 8. 个性化配置
|
||||||
|
|
||||||
## 9. 个性化配置
|
|
||||||
|
|
||||||
当用户的个性化信息与上文冲突时,以用户的个性化信息为准。
|
当用户的个性化信息与上文冲突时,以用户的个性化信息为准。
|
||||||
|
|||||||
12
prompts/workspace_system.txt
Normal file
12
prompts/workspace_system.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
## 工作区信息
|
||||||
|
|
||||||
|
- **运行环境**:{runtime_environment}
|
||||||
|
- **资源限制**:{resource_limit}
|
||||||
|
- **当前时间**:{current_time}
|
||||||
|
- **项目结构**:
|
||||||
|
|
||||||
|
```
|
||||||
|
{file_tree}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **长期记忆**:{memory}
|
||||||
@ -63,6 +63,7 @@
|
|||||||
</span>
|
</span>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<p class="section-note">仅作用于当前工作区,可随时在左下角开关。</p>
|
||||||
<div class="personalization-sections">
|
<div class="personalization-sections">
|
||||||
<div class="personal-left-column">
|
<div class="personal-left-column">
|
||||||
<div class="personal-section personal-info">
|
<div class="personal-section personal-info">
|
||||||
@ -254,25 +255,6 @@
|
|||||||
Qwen-Max 仅支持快速模式;Qwen-VL 不支持深度思考模式,选择时会给出提示。
|
Qwen-Max 仅支持快速模式;Qwen-VL 不支持深度思考模式,选择时会给出提示。
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="personal-actions-row">
|
|
||||||
<div class="personal-form-actions card-aligned">
|
|
||||||
<div class="personal-status-group">
|
|
||||||
<transition name="personal-status-fade">
|
|
||||||
<span class="status success" v-if="status">{{ status }}</span>
|
|
||||||
</transition>
|
|
||||||
<transition name="personal-status-fade">
|
|
||||||
<span class="status error" v-if="error">{{ error }}</span>
|
|
||||||
</transition>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="primary" :disabled="saving">
|
|
||||||
{{ saving ? '保存中...' : '保存设置' }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section v-else-if="activeTab === 'behavior'" key="behavior" class="personal-page behavior-page">
|
|
||||||
<div class="behavior-section">
|
|
||||||
<div class="behavior-field">
|
<div class="behavior-field">
|
||||||
<div class="behavior-field-header">
|
<div class="behavior-field-header">
|
||||||
<span class="field-title">默认思考模型</span>
|
<span class="field-title">默认思考模型</span>
|
||||||
@ -296,75 +278,6 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="behavior-field">
|
|
||||||
<div class="behavior-field-header">
|
|
||||||
<span class="field-title">堆叠块显示</span>
|
|
||||||
<p class="field-desc">使用新版堆叠动画展示思考/工具块,超过 6 条自动收纳为“更多”。默认开启。</p>
|
|
||||||
</div>
|
|
||||||
<label class="toggle-row">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
:checked="experiments.stackedBlocksEnabled"
|
|
||||||
@change="handleStackedBlocksToggle($event)"
|
|
||||||
/>
|
|
||||||
<span class="fancy-check" aria-hidden="true">
|
|
||||||
<svg viewBox="0 0 64 64">
|
|
||||||
<path
|
|
||||||
d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
|
|
||||||
pathLength="575.0541381835938"
|
|
||||||
class="fancy-path"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
<span>在对话区使用堆叠动画(可随时切换回传统列表)</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="behavior-field">
|
|
||||||
<div class="behavior-field-header">
|
|
||||||
<span class="field-title">自动生成对话标题</span>
|
|
||||||
<p class="field-desc">默认开启;关闭后标题将沿用首条消息。</p>
|
|
||||||
</div>
|
|
||||||
<label class="toggle-row">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
:checked="form.auto_generate_title"
|
|
||||||
@change="personalization.updateField({ key: 'auto_generate_title', value: $event.target.checked })"
|
|
||||||
/>
|
|
||||||
<span class="fancy-check" aria-hidden="true">
|
|
||||||
<svg viewBox="0 0 64 64">
|
|
||||||
<path
|
|
||||||
d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
|
|
||||||
pathLength="575.0541381835938"
|
|
||||||
class="fancy-path"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
<span>使用快速模型为新对话生成含 emoji 的简短标题</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="behavior-field">
|
|
||||||
<div class="behavior-field-header">
|
|
||||||
<span class="field-title">工具意图提示</span>
|
|
||||||
<p class="field-desc">开启后,调用工具时会先用约15字告诉你要做什么,替代“正在/完成”文案。</p>
|
|
||||||
</div>
|
|
||||||
<label class="toggle-row">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
:checked="form.tool_intent_enabled"
|
|
||||||
@change="personalization.updateField({ key: 'tool_intent_enabled', value: $event.target.checked })"
|
|
||||||
/>
|
|
||||||
<span class="fancy-check" aria-hidden="true">
|
|
||||||
<svg viewBox="0 0 64 64">
|
|
||||||
<path
|
|
||||||
d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
|
|
||||||
pathLength="575.0541381835938"
|
|
||||||
class="fancy-path"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
</span>
|
|
||||||
<span>在工具块显示“我要做什么”的简短提示</span>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div class="behavior-field">
|
<div class="behavior-field">
|
||||||
<div class="behavior-field-header">
|
<div class="behavior-field-header">
|
||||||
<span class="field-title">思考频率</span>
|
<span class="field-title">思考频率</span>
|
||||||
@ -401,11 +314,122 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="personal-actions-row">
|
||||||
|
<div class="personal-form-actions card-aligned">
|
||||||
|
<div class="personal-status-group">
|
||||||
|
<transition name="personal-status-fade">
|
||||||
|
<span class="status success" v-if="status">{{ status }}</span>
|
||||||
|
</transition>
|
||||||
|
<transition name="personal-status-fade">
|
||||||
|
<span class="status error" v-if="error">{{ error }}</span>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="primary" :disabled="saving">
|
||||||
|
{{ saving ? '保存中...' : '保存设置' }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section v-else-if="activeTab === 'behavior'" key="behavior" class="personal-page behavior-page">
|
||||||
|
<div class="behavior-section">
|
||||||
<div class="behavior-field">
|
<div class="behavior-field">
|
||||||
<div class="behavior-field-header">
|
<div class="behavior-field-header">
|
||||||
<span class="field-title">默认禁用工具类别</span>
|
<span class="field-title">堆叠块显示</span>
|
||||||
<p class="field-desc">选择后,这些类别在新任务中会保持关闭,也可随时通过快捷菜单临时开启。</p>
|
<p class="field-desc">使用新版堆叠动画展示思考/工具块,超过 6 条自动收纳为“更多”。默认开启。</p>
|
||||||
</div>
|
</div>
|
||||||
|
<label class="toggle-row">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:checked="experiments.stackedBlocksEnabled"
|
||||||
|
@change="handleStackedBlocksToggle($event)"
|
||||||
|
/>
|
||||||
|
<span class="fancy-check" aria-hidden="true">
|
||||||
|
<svg viewBox="0 0 64 64">
|
||||||
|
<path
|
||||||
|
d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
|
||||||
|
pathLength="575.0541381835938"
|
||||||
|
class="fancy-path"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>在对话区使用堆叠动画(可随时切换回传统列表)</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="behavior-field">
|
||||||
|
<div class="behavior-field-header">
|
||||||
|
<span class="field-title">静默禁用</span>
|
||||||
|
<p class="field-desc">禁用工具时不再注入提示消息,模型不会感知被禁用项。</p>
|
||||||
|
</div>
|
||||||
|
<label class="toggle-row">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:checked="form.silent_tool_disable"
|
||||||
|
@change="personalization.updateField({ key: 'silent_tool_disable', value: $event.target.checked })"
|
||||||
|
/>
|
||||||
|
<span class="fancy-check" aria-hidden="true">
|
||||||
|
<svg viewBox="0 0 64 64">
|
||||||
|
<path
|
||||||
|
d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
|
||||||
|
pathLength="575.0541381835938"
|
||||||
|
class="fancy-path"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>静默禁用工具(不向模型提示)</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="behavior-field">
|
||||||
|
<div class="behavior-field-header">
|
||||||
|
<span class="field-title">自动生成对话标题</span>
|
||||||
|
<p class="field-desc">默认开启;关闭后标题将沿用首条消息。</p>
|
||||||
|
</div>
|
||||||
|
<label class="toggle-row">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:checked="form.auto_generate_title"
|
||||||
|
@change="personalization.updateField({ key: 'auto_generate_title', value: $event.target.checked })"
|
||||||
|
/>
|
||||||
|
<span class="fancy-check" aria-hidden="true">
|
||||||
|
<svg viewBox="0 0 64 64">
|
||||||
|
<path
|
||||||
|
d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
|
||||||
|
pathLength="575.0541381835938"
|
||||||
|
class="fancy-path"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>使用快速模型为新对话生成含 emoji 的简短标题</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="behavior-field">
|
||||||
|
<div class="behavior-field-header">
|
||||||
|
<span class="field-title">工具意图提示</span>
|
||||||
|
<p class="field-desc">开启后,调用工具时会先用约15字告诉你要做什么,替代“正在/完成”文案。</p>
|
||||||
|
</div>
|
||||||
|
<label class="toggle-row">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
:checked="form.tool_intent_enabled"
|
||||||
|
@change="personalization.updateField({ key: 'tool_intent_enabled', value: $event.target.checked })"
|
||||||
|
/>
|
||||||
|
<span class="fancy-check" aria-hidden="true">
|
||||||
|
<svg viewBox="0 0 64 64">
|
||||||
|
<path
|
||||||
|
d="M 0 16 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 16 L 32 48 L 64 16 V 8 A 8 8 90 0 0 56 0 H 8 A 8 8 90 0 0 0 8 V 56 A 8 8 90 0 0 8 64 H 56 A 8 8 90 0 0 64 56 V 16"
|
||||||
|
pathLength="575.0541381835938"
|
||||||
|
class="fancy-path"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span>在工具块显示“我要做什么”的简短提示</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="behavior-field">
|
||||||
|
<div class="behavior-field-header">
|
||||||
|
<span class="field-title">默认禁用工具类别</span>
|
||||||
|
<p class="field-desc">选择后,这些类别在新任务中会保持关闭,也可随时通过快捷菜单临时开启。</p>
|
||||||
|
</div>
|
||||||
<div class="tool-category-grid" v-if="toolCategories.length">
|
<div class="tool-category-grid" v-if="toolCategories.length">
|
||||||
<label
|
<label
|
||||||
v-for="category in toolCategories"
|
v-for="category in toolCategories"
|
||||||
@ -617,9 +641,9 @@ const {
|
|||||||
} = storeToRefs(personalization);
|
} = storeToRefs(personalization);
|
||||||
|
|
||||||
const baseTabs = [
|
const baseTabs = [
|
||||||
{ id: 'preferences', label: '个性化设置' },
|
{ id: 'preferences', label: '个性化设置', description: '称呼、语气与注意事项' },
|
||||||
{ id: 'model', label: '模型偏好', description: '默认模型选择' },
|
{ id: 'model', label: '模型偏好', description: '默认模型选择' },
|
||||||
{ id: 'behavior', label: '模型行为' },
|
{ id: 'behavior', label: '模型行为', description: '工具提示与界面表现' },
|
||||||
{ id: 'image', label: '图片压缩', description: '发送图片的尺寸策略' },
|
{ id: 'image', label: '图片压缩', description: '发送图片的尺寸策略' },
|
||||||
{ id: 'theme', label: '主题切换', description: '浅色 / 深色 / Claude' },
|
{ id: 'theme', label: '主题切换', description: '浅色 / 深色 / Claude' },
|
||||||
{ id: 'experiments', label: '实验功能', description: 'Liquid Glass' }
|
{ id: 'experiments', label: '实验功能', description: 'Liquid Glass' }
|
||||||
@ -935,6 +959,12 @@ const applyThemeOption = (theme: ThemeKey) => {
|
|||||||
color: var(--claude-text-secondary);
|
color: var(--claude-text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.section-note {
|
||||||
|
margin: 6px 0 14px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: var(--claude-text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
.admin-monitor-actions {
|
.admin-monitor-actions {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@ -6,6 +6,7 @@ interface PersonalForm {
|
|||||||
enabled: boolean;
|
enabled: boolean;
|
||||||
auto_generate_title: boolean;
|
auto_generate_title: boolean;
|
||||||
tool_intent_enabled: boolean;
|
tool_intent_enabled: boolean;
|
||||||
|
silent_tool_disable: boolean;
|
||||||
self_identify: string;
|
self_identify: string;
|
||||||
user_name: string;
|
user_name: string;
|
||||||
profession: string;
|
profession: string;
|
||||||
@ -58,6 +59,7 @@ const defaultForm = (): PersonalForm => ({
|
|||||||
enabled: false,
|
enabled: false,
|
||||||
auto_generate_title: true,
|
auto_generate_title: true,
|
||||||
tool_intent_enabled: true,
|
tool_intent_enabled: true,
|
||||||
|
silent_tool_disable: false,
|
||||||
self_identify: '',
|
self_identify: '',
|
||||||
user_name: '',
|
user_name: '',
|
||||||
profession: '',
|
profession: '',
|
||||||
@ -186,6 +188,7 @@ export const usePersonalizationStore = defineStore('personalization', {
|
|||||||
enabled: !!data.enabled,
|
enabled: !!data.enabled,
|
||||||
auto_generate_title: data.auto_generate_title !== false,
|
auto_generate_title: data.auto_generate_title !== false,
|
||||||
tool_intent_enabled: !!data.tool_intent_enabled,
|
tool_intent_enabled: !!data.tool_intent_enabled,
|
||||||
|
silent_tool_disable: !!data.silent_tool_disable,
|
||||||
self_identify: data.self_identify || '',
|
self_identify: data.self_identify || '',
|
||||||
user_name: data.user_name || '',
|
user_name: data.user_name || '',
|
||||||
profession: data.profession || '',
|
profession: data.profession || '',
|
||||||
|
|||||||
@ -265,9 +265,16 @@
|
|||||||
background: var(--theme-surface-soft);
|
background: var(--theme-surface-soft);
|
||||||
align-self: flex-start;
|
align-self: flex-start;
|
||||||
height: auto;
|
height: auto;
|
||||||
max-height: none;
|
max-height: 72vh;
|
||||||
overflow: visible;
|
overflow-y: auto;
|
||||||
flex-wrap: wrap;
|
overflow-x: hidden;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
-ms-overflow-style: none; /* IE/Edge */
|
||||||
|
scrollbar-width: none; /* Firefox */
|
||||||
|
}
|
||||||
|
.personal-page-tabs::-webkit-scrollbar {
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.personal-tab-button {
|
.personal-tab-button {
|
||||||
|
|||||||
@ -98,6 +98,7 @@ class MainTerminal:
|
|||||||
data_dir=str(self.data_dir)
|
data_dir=str(self.data_dir)
|
||||||
)
|
)
|
||||||
self._announced_sub_agent_tasks = set()
|
self._announced_sub_agent_tasks = set()
|
||||||
|
self.silent_tool_disable = False # 是否静默工具禁用提示
|
||||||
|
|
||||||
# 聚焦文件管理
|
# 聚焦文件管理
|
||||||
self.focused_files = {} # {path: content} 存储聚焦的文件内容
|
self.focused_files = {} # {path: content} 存储聚焦的文件内容
|
||||||
@ -439,6 +440,8 @@ class MainTerminal:
|
|||||||
|
|
||||||
def _format_disabled_tool_notice(self) -> Optional[str]:
|
def _format_disabled_tool_notice(self) -> Optional[str]:
|
||||||
"""生成禁用工具提示信息 / Format disabled tool notice."""
|
"""生成禁用工具提示信息 / Format disabled tool notice."""
|
||||||
|
if getattr(self, "silent_tool_disable", False):
|
||||||
|
return None
|
||||||
if not self.disabled_notice_tools:
|
if not self.disabled_notice_tools:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -2126,6 +2129,10 @@ class MainTerminal:
|
|||||||
{"role": "system", "content": system_prompt}
|
{"role": "system", "content": system_prompt}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
workspace_system = self.context_manager._build_workspace_system_message(context)
|
||||||
|
if workspace_system:
|
||||||
|
messages.append({"role": "system", "content": workspace_system})
|
||||||
|
|
||||||
if self.tool_category_states.get("todo", True):
|
if self.tool_category_states.get("todo", True):
|
||||||
todo_prompt = self.load_prompt("todo_guidelines").strip()
|
todo_prompt = self.load_prompt("todo_guidelines").strip()
|
||||||
if todo_prompt:
|
if todo_prompt:
|
||||||
|
|||||||
@ -16,6 +16,8 @@ try:
|
|||||||
TERMINAL_SANDBOX_CPUS,
|
TERMINAL_SANDBOX_CPUS,
|
||||||
TERMINAL_SANDBOX_MEMORY,
|
TERMINAL_SANDBOX_MEMORY,
|
||||||
PROJECT_MAX_STORAGE_MB,
|
PROJECT_MAX_STORAGE_MB,
|
||||||
|
TERMINAL_SANDBOX_MODE,
|
||||||
|
LINUX_SAFETY,
|
||||||
)
|
)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
import sys
|
import sys
|
||||||
@ -31,6 +33,8 @@ except ImportError:
|
|||||||
TERMINAL_SANDBOX_CPUS,
|
TERMINAL_SANDBOX_CPUS,
|
||||||
TERMINAL_SANDBOX_MEMORY,
|
TERMINAL_SANDBOX_MEMORY,
|
||||||
PROJECT_MAX_STORAGE_MB,
|
PROJECT_MAX_STORAGE_MB,
|
||||||
|
TERMINAL_SANDBOX_MODE,
|
||||||
|
LINUX_SAFETY,
|
||||||
)
|
)
|
||||||
from utils.conversation_manager import ConversationManager
|
from utils.conversation_manager import ConversationManager
|
||||||
|
|
||||||
@ -67,6 +71,10 @@ class ContextManager:
|
|||||||
self._focused_files = {}
|
self._focused_files = {}
|
||||||
|
|
||||||
self.load_annotations()
|
self.load_annotations()
|
||||||
|
|
||||||
|
def _is_host_mode_without_safety(self) -> bool:
|
||||||
|
"""是否处于宿主机模式且未启用安全保护。"""
|
||||||
|
return (TERMINAL_SANDBOX_MODE or "").lower() == "host" and not LINUX_SAFETY
|
||||||
|
|
||||||
def set_web_terminal_callback(self, callback):
|
def set_web_terminal_callback(self, callback):
|
||||||
"""设置Web终端回调函数,用于广播事件"""
|
"""设置Web终端回调函数,用于广播事件"""
|
||||||
@ -954,14 +962,17 @@ class ContextManager:
|
|||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
project_name = Path(structure['path']).name
|
project_name = Path(structure['path']).name
|
||||||
container_root = (self.container_mount_path or "").strip() or "/workspace"
|
if self._is_host_mode_without_safety():
|
||||||
container_root = container_root.rstrip("/") or "/"
|
root_label = f"{structure['path']} (项目根)"
|
||||||
if container_root == "/":
|
|
||||||
root_label = f"/ (项目根)"
|
|
||||||
elif container_root.endswith(project_name):
|
|
||||||
root_label = f"{container_root} (项目根)"
|
|
||||||
else:
|
else:
|
||||||
root_label = f"{container_root} (映射自 {project_name})"
|
container_root = (self.container_mount_path or "").strip() or "/workspace"
|
||||||
|
container_root = container_root.rstrip("/") or "/"
|
||||||
|
if container_root == "/":
|
||||||
|
root_label = f"/ (项目根)"
|
||||||
|
elif container_root.endswith(project_name):
|
||||||
|
root_label = f"{container_root} (项目根)"
|
||||||
|
else:
|
||||||
|
root_label = f"{container_root} (映射自 {project_name})"
|
||||||
lines.append(f"📁 {root_label}/")
|
lines.append(f"📁 {root_label}/")
|
||||||
|
|
||||||
def build_tree_recursive(tree_dict: Dict, prefix: str = ""):
|
def build_tree_recursive(tree_dict: Dict, prefix: str = ""):
|
||||||
@ -1116,6 +1127,45 @@ class ContextManager:
|
|||||||
"is_overflow": sizes["total"] > MAX_CONTEXT_SIZE,
|
"is_overflow": sizes["total"] > MAX_CONTEXT_SIZE,
|
||||||
"usage_percent": (sizes["total"] / MAX_CONTEXT_SIZE) * 100
|
"usage_percent": (sizes["total"] / MAX_CONTEXT_SIZE) * 100
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def _build_workspace_system_message(self, context: Dict) -> Optional[str]:
|
||||||
|
"""构建独立的工作区系统消息,根据运行模式动态展示环境与资源信息。"""
|
||||||
|
template = self.load_prompt("workspace_system")
|
||||||
|
if not template:
|
||||||
|
template = (
|
||||||
|
"## 工作区信息\n"
|
||||||
|
"- **运行环境**:{runtime_environment}\n"
|
||||||
|
"- **资源限制**:{resource_limit}\n"
|
||||||
|
"- **当前时间**:{current_time}\n"
|
||||||
|
"- **项目结构**:\n\n{file_tree}\n\n"
|
||||||
|
"- **长期记忆**:{memory}"
|
||||||
|
)
|
||||||
|
|
||||||
|
is_host = self._is_host_mode_without_safety()
|
||||||
|
runtime_environment = (
|
||||||
|
"宿主机模式"
|
||||||
|
if is_host
|
||||||
|
else f"隔离容器中(挂载目录 {self.container_mount_path or '/workspace'}),宿主机路径已隐藏"
|
||||||
|
)
|
||||||
|
resource_limit = (
|
||||||
|
"宿主机模式无限制"
|
||||||
|
if is_host
|
||||||
|
else f"CPU {self.container_cpu_limit} 核,内存 {self.container_memory_limit},磁盘配额 {self.project_storage_limit}"
|
||||||
|
)
|
||||||
|
|
||||||
|
content = template.format(
|
||||||
|
runtime_environment=runtime_environment,
|
||||||
|
resource_limit=resource_limit,
|
||||||
|
container_path=self.container_mount_path or "/workspace",
|
||||||
|
container_cpus=self.container_cpu_limit,
|
||||||
|
container_memory=self.container_memory_limit,
|
||||||
|
project_storage=self.project_storage_limit,
|
||||||
|
current_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
file_tree=context["project_info"]["file_tree"],
|
||||||
|
memory=context["memory"],
|
||||||
|
)
|
||||||
|
|
||||||
|
return content
|
||||||
def build_messages(self, context: Dict, user_input: str) -> List[Dict]:
|
def build_messages(self, context: Dict, user_input: str) -> List[Dict]:
|
||||||
"""构建消息列表(添加终端内容注入)"""
|
"""构建消息列表(添加终端内容注入)"""
|
||||||
# 加载系统提示
|
# 加载系统提示
|
||||||
@ -1140,6 +1190,10 @@ class ContextManager:
|
|||||||
messages = [
|
messages = [
|
||||||
{"role": "system", "content": system_prompt}
|
{"role": "system", "content": system_prompt}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
workspace_system = self._build_workspace_system_message(context)
|
||||||
|
if workspace_system:
|
||||||
|
messages.append({"role": "system", "content": workspace_system})
|
||||||
|
|
||||||
# 添加对话历史
|
# 添加对话历史
|
||||||
for conv in context["conversation"]:
|
for conv in context["conversation"]:
|
||||||
|
|||||||
@ -18,6 +18,8 @@ try:
|
|||||||
TERMINAL_SANDBOX_CPUS,
|
TERMINAL_SANDBOX_CPUS,
|
||||||
TERMINAL_SANDBOX_MEMORY,
|
TERMINAL_SANDBOX_MEMORY,
|
||||||
PROJECT_MAX_STORAGE_MB,
|
PROJECT_MAX_STORAGE_MB,
|
||||||
|
TERMINAL_SANDBOX_MODE,
|
||||||
|
LINUX_SAFETY,
|
||||||
)
|
)
|
||||||
from config.model_profiles import get_model_prompt_replacements
|
from config.model_profiles import get_model_prompt_replacements
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -34,6 +36,8 @@ except ImportError:
|
|||||||
TERMINAL_SANDBOX_CPUS,
|
TERMINAL_SANDBOX_CPUS,
|
||||||
TERMINAL_SANDBOX_MEMORY,
|
TERMINAL_SANDBOX_MEMORY,
|
||||||
PROJECT_MAX_STORAGE_MB,
|
PROJECT_MAX_STORAGE_MB,
|
||||||
|
TERMINAL_SANDBOX_MODE,
|
||||||
|
LINUX_SAFETY,
|
||||||
)
|
)
|
||||||
from config.model_profiles import get_model_prompt_replacements
|
from config.model_profiles import get_model_prompt_replacements
|
||||||
from utils.conversation_manager import ConversationManager
|
from utils.conversation_manager import ConversationManager
|
||||||
@ -70,6 +74,10 @@ class ContextManager:
|
|||||||
|
|
||||||
self.load_annotations()
|
self.load_annotations()
|
||||||
|
|
||||||
|
def _is_host_mode_without_safety(self) -> bool:
|
||||||
|
"""是否处于宿主机模式且未启用安全保护。"""
|
||||||
|
return (TERMINAL_SANDBOX_MODE or "").lower() == "host" and not LINUX_SAFETY
|
||||||
|
|
||||||
# ===========================================
|
# ===========================================
|
||||||
# Token 累计文件工具
|
# Token 累计文件工具
|
||||||
# ===========================================
|
# ===========================================
|
||||||
@ -1109,14 +1117,17 @@ class ContextManager:
|
|||||||
|
|
||||||
lines = []
|
lines = []
|
||||||
project_name = Path(structure['path']).name
|
project_name = Path(structure['path']).name
|
||||||
container_root = (self.container_mount_path or "").strip() or "/workspace"
|
if self._is_host_mode_without_safety():
|
||||||
container_root = container_root.rstrip("/") or "/"
|
root_label = f"{structure['path']} (项目根)"
|
||||||
if container_root == "/":
|
|
||||||
root_label = f"/ (项目根)"
|
|
||||||
elif container_root.endswith(project_name):
|
|
||||||
root_label = f"{container_root} (项目根)"
|
|
||||||
else:
|
else:
|
||||||
root_label = f"{container_root} (映射自 {project_name})"
|
container_root = (self.container_mount_path or "").strip() or "/workspace"
|
||||||
|
container_root = container_root.rstrip("/") or "/"
|
||||||
|
if container_root == "/":
|
||||||
|
root_label = f"/ (项目根)"
|
||||||
|
elif container_root.endswith(project_name):
|
||||||
|
root_label = f"{container_root} (项目根)"
|
||||||
|
else:
|
||||||
|
root_label = f"{container_root} (映射自 {project_name})"
|
||||||
lines.append(f"📁 {root_label}/")
|
lines.append(f"📁 {root_label}/")
|
||||||
|
|
||||||
ROOT_FOLDER_CHILD_LIMIT = 20
|
ROOT_FOLDER_CHILD_LIMIT = 20
|
||||||
@ -1371,13 +1382,52 @@ class ContextManager:
|
|||||||
continue
|
continue
|
||||||
return parts if parts else text
|
return parts if parts else text
|
||||||
|
|
||||||
|
def _build_workspace_system_message(self, context: Dict) -> Optional[str]:
|
||||||
|
"""构建独立的工作区系统消息,根据运行模式动态展示环境与资源信息。"""
|
||||||
|
template = self.load_prompt("workspace_system")
|
||||||
|
if not template:
|
||||||
|
template = (
|
||||||
|
"## 工作区信息\n"
|
||||||
|
"- **运行环境**:{runtime_environment}\n"
|
||||||
|
"- **资源限制**:{resource_limit}\n"
|
||||||
|
"- **当前时间**:{current_time}\n"
|
||||||
|
"- **项目结构**:\n\n{file_tree}\n\n"
|
||||||
|
"- **长期记忆**:{memory}"
|
||||||
|
)
|
||||||
|
|
||||||
|
is_host = self._is_host_mode_without_safety()
|
||||||
|
runtime_environment = (
|
||||||
|
"宿主机模式"
|
||||||
|
if is_host
|
||||||
|
else f"隔离容器中(挂载目录 {self.container_mount_path or '/workspace'}),宿主机路径已隐藏"
|
||||||
|
)
|
||||||
|
resource_limit = (
|
||||||
|
"宿主机模式无限制"
|
||||||
|
if is_host
|
||||||
|
else f"CPU {self.container_cpu_limit} 核,内存 {self.container_memory_limit},磁盘配额 {self.project_storage_limit}"
|
||||||
|
)
|
||||||
|
|
||||||
|
content = template.format(
|
||||||
|
runtime_environment=runtime_environment,
|
||||||
|
resource_limit=resource_limit,
|
||||||
|
container_path=self.container_mount_path or "/workspace",
|
||||||
|
container_cpus=self.container_cpu_limit,
|
||||||
|
container_memory=self.container_memory_limit,
|
||||||
|
project_storage=self.project_storage_limit,
|
||||||
|
current_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
|
file_tree=context["project_info"]["file_tree"],
|
||||||
|
memory=context["memory"],
|
||||||
|
)
|
||||||
|
|
||||||
|
return content
|
||||||
|
|
||||||
def build_messages(self, context: Dict, user_input: str) -> List[Dict]:
|
def build_messages(self, context: Dict, user_input: str) -> List[Dict]:
|
||||||
"""构建消息列表(添加终端内容注入)"""
|
"""构建消息列表(添加终端内容注入)"""
|
||||||
# 加载系统提示(Qwen-VL 使用专用提示)
|
# 加载系统提示(Qwen-VL 使用专用提示)
|
||||||
model_key = getattr(self.main_terminal, "model_key", "kimi") if hasattr(self, "main_terminal") else "kimi"
|
model_key = getattr(self.main_terminal, "model_key", "kimi") if hasattr(self, "main_terminal") else "kimi"
|
||||||
prompt_name = "main_system_qwenvl" if model_key in {"qwen3-vl-plus", "kimi-k2.5"} else "main_system"
|
prompt_name = "main_system_qwenvl" if model_key in {"qwen3-vl-plus", "kimi-k2.5"} else "main_system"
|
||||||
system_prompt = self.load_prompt(prompt_name)
|
system_prompt = self.load_prompt(prompt_name)
|
||||||
|
|
||||||
# 格式化系统提示
|
# 格式化系统提示
|
||||||
container_path = self.container_mount_path or "/workspace"
|
container_path = self.container_mount_path or "/workspace"
|
||||||
container_cpus = self.container_cpu_limit
|
container_cpus = self.container_cpu_limit
|
||||||
@ -1395,11 +1445,15 @@ class ContextManager:
|
|||||||
current_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
current_time=datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
|
||||||
model_description=prompt_replacements.get("model_description", "")
|
model_description=prompt_replacements.get("model_description", "")
|
||||||
)
|
)
|
||||||
|
|
||||||
messages = [
|
messages = [
|
||||||
{"role": "system", "content": system_prompt}
|
{"role": "system", "content": system_prompt}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
workspace_system = self._build_workspace_system_message(context)
|
||||||
|
if workspace_system:
|
||||||
|
messages.append({"role": "system", "content": workspace_system})
|
||||||
|
|
||||||
# 添加对话历史
|
# 添加对话历史
|
||||||
for conv in context["conversation"]:
|
for conv in context["conversation"]:
|
||||||
if conv["role"] == "assistant":
|
if conv["role"] == "assistant":
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user