feat(memory): 新增项目记忆最大注入条数设置,记忆索引按最近修改排序
- 个人空间-上下文新增「最大记忆注入」(默认 20,最小 5,留空无上限) - 提示词中项目记忆索引从文件名字典序改为按 mtime 倒序注入 - 超上限时截断并注入说明:共 N 条、仅注入前 x 条、其余用 search_project_memory 检索 - 修复 memory_system 模板条件块只删标记不删占位文字导致的「暂无xx记忆」残留
This commit is contained in:
parent
16900b0a20
commit
56c067b710
@ -1,5 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, List, Optional, Set
|
from typing import Any, Dict, List, Optional, Set
|
||||||
|
|
||||||
@ -55,6 +56,7 @@ from modules.easter_egg_manager import EasterEggManager
|
|||||||
from modules.personalization_manager import (
|
from modules.personalization_manager import (
|
||||||
load_personalization_config,
|
load_personalization_config,
|
||||||
build_personalization_prompt,
|
build_personalization_prompt,
|
||||||
|
resolve_project_memory_inject_limit,
|
||||||
RECENT_CONVERSATIONS_PROMPT_LIMIT_MIN,
|
RECENT_CONVERSATIONS_PROMPT_LIMIT_MIN,
|
||||||
RECENT_CONVERSATIONS_PROMPT_LIMIT_MAX,
|
RECENT_CONVERSATIONS_PROMPT_LIMIT_MAX,
|
||||||
RECENT_CONVERSATIONS_PROMPT_LIMIT_DEFAULT,
|
RECENT_CONVERSATIONS_PROMPT_LIMIT_DEFAULT,
|
||||||
@ -89,11 +91,19 @@ logger = setup_logger(__name__)
|
|||||||
DISABLE_LENGTH_CHECK = True
|
DISABLE_LENGTH_CHECK = True
|
||||||
|
|
||||||
|
|
||||||
|
def _render_optional_block(text: str, tag: str, keep: bool) -> str:
|
||||||
|
"""渲染 [tag]...[/tag] 条件块:keep=True 去掉标记保留内容;keep=False 整块(含内容)删除。"""
|
||||||
|
pattern = re.compile(r"\[" + re.escape(tag) + r"\](.*?)\[/" + re.escape(tag) + r"\]", re.DOTALL)
|
||||||
|
if keep:
|
||||||
|
return pattern.sub(lambda m: m.group(1), text)
|
||||||
|
return pattern.sub("", text)
|
||||||
|
|
||||||
|
|
||||||
class MemoryMixin:
|
class MemoryMixin:
|
||||||
"""MainTerminalContextMixin memory 能力 mixin。"""
|
"""MainTerminalContextMixin memory 能力 mixin。"""
|
||||||
|
|
||||||
def _scan_project_memories(self):
|
def _scan_project_memories(self):
|
||||||
"""扫描 .astrion/memory/*.md 并解析 frontmatter 中的 name 和 description"""
|
"""扫描 .astrion/memory/*.md 并解析 frontmatter 中的 name 和 description,按最近修改时间倒序返回"""
|
||||||
try:
|
try:
|
||||||
memory_dir = Path(self.project_path) / WORKSPACE_MEMORY_DIRNAME
|
memory_dir = Path(self.project_path) / WORKSPACE_MEMORY_DIRNAME
|
||||||
except Exception:
|
except Exception:
|
||||||
@ -120,9 +130,12 @@ class MemoryMixin:
|
|||||||
"file": md_file.name,
|
"file": md_file.name,
|
||||||
"name": name or md_file.stem,
|
"name": name or md_file.stem,
|
||||||
"description": description or "",
|
"description": description or "",
|
||||||
|
"mtime": md_file.stat().st_mtime,
|
||||||
})
|
})
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
# 最近修改的排前面;mtime 相同时保持文件名顺序(sorted 基数 + 稳定排序)
|
||||||
|
results.sort(key=lambda item: item.get("mtime", 0), reverse=True)
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def _build_memory_system_content(self) -> str:
|
def _build_memory_system_content(self) -> str:
|
||||||
@ -137,10 +150,23 @@ class MemoryMixin:
|
|||||||
except Exception:
|
except Exception:
|
||||||
global_memory_text = ""
|
global_memory_text = ""
|
||||||
|
|
||||||
|
try:
|
||||||
|
personalization_config = (
|
||||||
|
getattr(self.context_manager, "custom_personalization_config", None)
|
||||||
|
or load_personalization_config(self.data_dir)
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
personalization_config = None
|
||||||
|
inject_limit = resolve_project_memory_inject_limit(personalization_config)
|
||||||
|
|
||||||
project_memories = self._scan_project_memories()
|
project_memories = self._scan_project_memories()
|
||||||
if project_memories:
|
total_count = len(project_memories)
|
||||||
|
truncated = inject_limit is not None and total_count > inject_limit
|
||||||
|
shown_memories = project_memories[:inject_limit] if truncated else project_memories
|
||||||
|
|
||||||
|
if shown_memories:
|
||||||
lines = []
|
lines = []
|
||||||
for m in project_memories:
|
for m in shown_memories:
|
||||||
desc = m.get("description", "")
|
desc = m.get("description", "")
|
||||||
if desc:
|
if desc:
|
||||||
lines.append(f".astrion/memory/{m['file']}:{desc}")
|
lines.append(f".astrion/memory/{m['file']}:{desc}")
|
||||||
@ -151,16 +177,16 @@ class MemoryMixin:
|
|||||||
project_memory_list = ""
|
project_memory_list = ""
|
||||||
|
|
||||||
result = template
|
result = template
|
||||||
if global_memory_text:
|
result = result.replace("{global_memory}", global_memory_text)
|
||||||
result = result.replace("{global_memory}", global_memory_text)
|
result = _render_optional_block(result, "global_memory_empty", keep=not global_memory_text)
|
||||||
result = result.replace("[global_memory_empty]", "").replace("[/global_memory_empty]", "")
|
|
||||||
else:
|
|
||||||
result = result.replace("{global_memory}", "")
|
|
||||||
|
|
||||||
if project_memory_list:
|
result = result.replace("{project_memory_list}", project_memory_list)
|
||||||
result = result.replace("{project_memory_list}", project_memory_list)
|
result = _render_optional_block(result, "project_memory_empty", keep=not project_memories)
|
||||||
result = result.replace("[project_memory_empty]", "").replace("[/project_memory_empty]", "")
|
|
||||||
else:
|
if truncated:
|
||||||
result = result.replace("{project_memory_list}", "")
|
result = result.replace("{project_memory_total}", str(total_count))
|
||||||
|
result = result.replace("{project_memory_limit}", str(inject_limit))
|
||||||
|
result = result.replace("{project_memory_remaining}", str(total_count - inject_limit))
|
||||||
|
result = _render_optional_block(result, "project_memory_truncated", keep=truncated)
|
||||||
|
|
||||||
return result.strip()
|
return result.strip()
|
||||||
|
|||||||
@ -37,6 +37,9 @@ TONE_PRESETS = ["健谈", "幽默", "直言不讳", "鼓励性", "诗意", "企
|
|||||||
RECENT_CONVERSATIONS_PROMPT_LIMIT_MIN = 1
|
RECENT_CONVERSATIONS_PROMPT_LIMIT_MIN = 1
|
||||||
RECENT_CONVERSATIONS_PROMPT_LIMIT_MAX = 30
|
RECENT_CONVERSATIONS_PROMPT_LIMIT_MAX = 30
|
||||||
RECENT_CONVERSATIONS_PROMPT_LIMIT_DEFAULT = 10
|
RECENT_CONVERSATIONS_PROMPT_LIMIT_DEFAULT = 10
|
||||||
|
PROJECT_MEMORY_INJECT_LIMIT_MIN = 5
|
||||||
|
PROJECT_MEMORY_INJECT_LIMIT_DEFAULT = 20
|
||||||
|
PROJECT_MEMORY_INJECT_LIMIT_MAX = 100_000 # 防御性上限;None 表示无上限
|
||||||
DEFAULT_SHALLOW_COMPRESS_TRIGGER_TOKENS = 80_000
|
DEFAULT_SHALLOW_COMPRESS_TRIGGER_TOKENS = 80_000
|
||||||
DEFAULT_SHALLOW_COMPRESS_KEEP_RECENT_TOOLS = 15
|
DEFAULT_SHALLOW_COMPRESS_KEEP_RECENT_TOOLS = 15
|
||||||
DEFAULT_SHALLOW_COMPRESS_MAX_REPLACE_PER_ROUND = 10
|
DEFAULT_SHALLOW_COMPRESS_MAX_REPLACE_PER_ROUND = 10
|
||||||
@ -73,6 +76,7 @@ DEFAULT_PERSONALIZATION_CONFIG: Dict[str, Any] = {
|
|||||||
"auto_generate_title": True,
|
"auto_generate_title": True,
|
||||||
"recent_conversations_prompt_enabled": False,
|
"recent_conversations_prompt_enabled": False,
|
||||||
"recent_conversations_prompt_limit": RECENT_CONVERSATIONS_PROMPT_LIMIT_DEFAULT,
|
"recent_conversations_prompt_limit": RECENT_CONVERSATIONS_PROMPT_LIMIT_DEFAULT,
|
||||||
|
"project_memory_inject_limit": PROJECT_MEMORY_INJECT_LIMIT_DEFAULT, # 项目记忆索引最大注入条数:None-无上限 / >=5-该值
|
||||||
"tool_intent_enabled": True,
|
"tool_intent_enabled": True,
|
||||||
"skill_hints_enabled": False, # Skill 提示系统开关(默认关闭)
|
"skill_hints_enabled": False, # Skill 提示系统开关(默认关闭)
|
||||||
"skill_strict_terminal_enabled": False, # 强约束:terminal 系列工具需先阅读 terminal-guide
|
"skill_strict_terminal_enabled": False, # 强约束:terminal 系列工具需先阅读 terminal-guide
|
||||||
@ -132,6 +136,9 @@ __all__ = [
|
|||||||
"RECENT_CONVERSATIONS_PROMPT_LIMIT_MIN",
|
"RECENT_CONVERSATIONS_PROMPT_LIMIT_MIN",
|
||||||
"RECENT_CONVERSATIONS_PROMPT_LIMIT_MAX",
|
"RECENT_CONVERSATIONS_PROMPT_LIMIT_MAX",
|
||||||
"RECENT_CONVERSATIONS_PROMPT_LIMIT_DEFAULT",
|
"RECENT_CONVERSATIONS_PROMPT_LIMIT_DEFAULT",
|
||||||
|
"PROJECT_MEMORY_INJECT_LIMIT_MIN",
|
||||||
|
"PROJECT_MEMORY_INJECT_LIMIT_DEFAULT",
|
||||||
|
"resolve_project_memory_inject_limit",
|
||||||
"load_personalization_config",
|
"load_personalization_config",
|
||||||
"save_personalization_config",
|
"save_personalization_config",
|
||||||
"ensure_personalization_config",
|
"ensure_personalization_config",
|
||||||
@ -659,6 +666,12 @@ def sanitize_personalization_payload(
|
|||||||
else:
|
else:
|
||||||
base["sub_agent_max_turns"] = _sanitize_sub_agent_max_turns(base.get("sub_agent_max_turns"))
|
base["sub_agent_max_turns"] = _sanitize_sub_agent_max_turns(base.get("sub_agent_max_turns"))
|
||||||
|
|
||||||
|
# 项目记忆索引最大注入条数(None-无上限 / >=5-该值,默认 20)
|
||||||
|
if "project_memory_inject_limit" in data:
|
||||||
|
base["project_memory_inject_limit"] = _sanitize_project_memory_inject_limit(data.get("project_memory_inject_limit"))
|
||||||
|
else:
|
||||||
|
base["project_memory_inject_limit"] = _sanitize_project_memory_inject_limit(base.get("project_memory_inject_limit"))
|
||||||
|
|
||||||
return base
|
return base
|
||||||
|
|
||||||
|
|
||||||
@ -675,6 +688,30 @@ def _sanitize_sub_agent_max_turns(value: Any) -> Optional[int]:
|
|||||||
return min(parsed, 100_000) # 防御性上限;需要更大时用 0 表示无上限
|
return min(parsed, 100_000) # 防御性上限;需要更大时用 0 表示无上限
|
||||||
|
|
||||||
|
|
||||||
|
def _sanitize_project_memory_inject_limit(value: Any) -> Optional[int]:
|
||||||
|
"""清洗项目记忆索引最大注入条数:None/''/0/负数 → None(无上限);非法值 → 默认 20;正整数钳到 [5, 100000]。"""
|
||||||
|
if value is None or value == "":
|
||||||
|
return None
|
||||||
|
if isinstance(value, bool):
|
||||||
|
return PROJECT_MEMORY_INJECT_LIMIT_DEFAULT
|
||||||
|
try:
|
||||||
|
parsed = int(value)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
return PROJECT_MEMORY_INJECT_LIMIT_DEFAULT
|
||||||
|
if parsed <= 0:
|
||||||
|
return None
|
||||||
|
return max(PROJECT_MEMORY_INJECT_LIMIT_MIN, min(parsed, PROJECT_MEMORY_INJECT_LIMIT_MAX))
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_project_memory_inject_limit(config: Any) -> Optional[int]:
|
||||||
|
"""从个性化配置取项目记忆注入上限:None-无上限;缺键/非法 → 默认 20。"""
|
||||||
|
if not isinstance(config, dict):
|
||||||
|
return PROJECT_MEMORY_INJECT_LIMIT_DEFAULT
|
||||||
|
if "project_memory_inject_limit" not in config:
|
||||||
|
return PROJECT_MEMORY_INJECT_LIMIT_DEFAULT
|
||||||
|
return _sanitize_project_memory_inject_limit(config.get("project_memory_inject_limit"))
|
||||||
|
|
||||||
|
|
||||||
def _sanitize_goal_end_conditions(value: Any) -> list:
|
def _sanitize_goal_end_conditions(value: Any) -> list:
|
||||||
"""清洗目标模式结束方式列表,保证至少包含 max_turns。"""
|
"""清洗目标模式结束方式列表,保证至少包含 max_turns。"""
|
||||||
cleaned: list = []
|
cleaned: list = []
|
||||||
|
|||||||
@ -6,10 +6,10 @@
|
|||||||
- 记忆内容为提示而非事实,执行前应与实际代码验证
|
- 记忆内容为提示而非事实,执行前应与实际代码验证
|
||||||
|
|
||||||
### 总体长期记忆
|
### 总体长期记忆
|
||||||
{global_memory}
|
{global_memory}[global_memory_empty]暂无总体长期记忆[/global_memory_empty]
|
||||||
[global_memory_empty]暂无总体长期记忆[/global_memory_empty]
|
|
||||||
|
|
||||||
### 项目记忆(.astrion/memory/)
|
### 项目记忆(.astrion/memory/)
|
||||||
{project_memory_list}
|
[project_memory_truncated]共 {project_memory_total} 条记忆,按最近修改排序,仅注入前 {project_memory_limit} 条索引:
|
||||||
[project_memory_empty]暂无项目记忆[/project_memory_empty]
|
[/project_memory_truncated]{project_memory_list}[project_memory_empty]暂无项目记忆[/project_memory_empty]
|
||||||
以上仅为索引(一句话描述)。处理项目相关任务前,用 search_project_memory 检索正文;定位后用 recall_project_memory 读全文。
|
[project_memory_truncated]其余 {project_memory_remaining} 条未注入(可用 search_project_memory 按关键词检索)。
|
||||||
|
[/project_memory_truncated]以上仅为索引(一句话描述)。处理项目相关任务前,用 search_project_memory 检索正文;定位后用 recall_project_memory 读全文。
|
||||||
|
|||||||
@ -22,6 +22,7 @@ from modules.personalization_manager import (
|
|||||||
save_personalization_config,
|
save_personalization_config,
|
||||||
RECENT_CONVERSATIONS_PROMPT_LIMIT_MIN,
|
RECENT_CONVERSATIONS_PROMPT_LIMIT_MIN,
|
||||||
RECENT_CONVERSATIONS_PROMPT_LIMIT_MAX,
|
RECENT_CONVERSATIONS_PROMPT_LIMIT_MAX,
|
||||||
|
PROJECT_MEMORY_INJECT_LIMIT_MIN,
|
||||||
)
|
)
|
||||||
from modules.skills_manager import (
|
from modules.skills_manager import (
|
||||||
get_skills_catalog,
|
get_skills_catalog,
|
||||||
@ -286,6 +287,10 @@ def get_personalization_settings(terminal: WebTerminal, workspace: UserWorkspace
|
|||||||
"recent_conversations_prompt_limit_range": {
|
"recent_conversations_prompt_limit_range": {
|
||||||
"min": RECENT_CONVERSATIONS_PROMPT_LIMIT_MIN,
|
"min": RECENT_CONVERSATIONS_PROMPT_LIMIT_MIN,
|
||||||
"max": RECENT_CONVERSATIONS_PROMPT_LIMIT_MAX,
|
"max": RECENT_CONVERSATIONS_PROMPT_LIMIT_MAX,
|
||||||
|
},
|
||||||
|
"project_memory_inject_limit_range": {
|
||||||
|
"min": PROJECT_MEMORY_INJECT_LIMIT_MIN,
|
||||||
|
"max": None,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
@ -372,6 +377,10 @@ def update_personalization_settings(terminal: WebTerminal, workspace: UserWorksp
|
|||||||
"recent_conversations_prompt_limit_range": {
|
"recent_conversations_prompt_limit_range": {
|
||||||
"min": RECENT_CONVERSATIONS_PROMPT_LIMIT_MIN,
|
"min": RECENT_CONVERSATIONS_PROMPT_LIMIT_MIN,
|
||||||
"max": RECENT_CONVERSATIONS_PROMPT_LIMIT_MAX,
|
"max": RECENT_CONVERSATIONS_PROMPT_LIMIT_MAX,
|
||||||
|
},
|
||||||
|
"project_memory_inject_limit_range": {
|
||||||
|
"min": PROJECT_MEMORY_INJECT_LIMIT_MIN,
|
||||||
|
"max": None,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
except ValueError as exc:
|
except ValueError as exc:
|
||||||
|
|||||||
@ -1087,6 +1087,21 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="settings-input-row">
|
||||||
|
<span class="settings-row-title">最大记忆注入</span>
|
||||||
|
<div class="settings-number-row">
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
:min="projectMemoryInjectLimitMin"
|
||||||
|
:value="form.project_memory_inject_limit ?? ''"
|
||||||
|
placeholder="无上限"
|
||||||
|
@input="handleProjectMemoryInjectLimitInput"
|
||||||
|
@blur="commitProjectMemoryInjectLimitInput"
|
||||||
|
/><button type="button" @click="restoreProjectMemoryInjectLimit">
|
||||||
|
恢复默认
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="settings-group-block">
|
<div class="settings-group-block">
|
||||||
<div class="settings-group-title">
|
<div class="settings-group-title">
|
||||||
<span class="settings-row-title">上下文压缩策略</span
|
<span class="settings-row-title">上下文压缩策略</span
|
||||||
@ -1940,6 +1955,7 @@ const {
|
|||||||
toolCategories,
|
toolCategories,
|
||||||
skillsCatalog,
|
skillsCatalog,
|
||||||
recentConversationsPromptLimitRange,
|
recentConversationsPromptLimitRange,
|
||||||
|
projectMemoryInjectLimitMin,
|
||||||
experiments
|
experiments
|
||||||
} = storeToRefs(personalization);
|
} = storeToRefs(personalization);
|
||||||
|
|
||||||
@ -2893,6 +2909,32 @@ const restoreRecentConversationsPromptLimit = () => {
|
|||||||
personalization.setRecentConversationsPromptLimit(null);
|
personalization.setRecentConversationsPromptLimit(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleProjectMemoryInjectLimitInput = (event: Event) => {
|
||||||
|
const target = event.target as HTMLInputElement | null;
|
||||||
|
if (!target) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
personalization.updateField({
|
||||||
|
key: 'project_memory_inject_limit',
|
||||||
|
value: target.value
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const commitProjectMemoryInjectLimitInput = (event: Event) => {
|
||||||
|
const target = event.target as HTMLInputElement | null;
|
||||||
|
if (!target || !target.value) {
|
||||||
|
// 留空 = 无上限
|
||||||
|
personalization.setProjectMemoryInjectLimit(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const parsed = Number(target.value);
|
||||||
|
personalization.setProjectMemoryInjectLimit(Number.isNaN(parsed) ? null : parsed);
|
||||||
|
};
|
||||||
|
|
||||||
|
const restoreProjectMemoryInjectLimit = () => {
|
||||||
|
personalization.restoreProjectMemoryInjectLimit();
|
||||||
|
};
|
||||||
|
|
||||||
const handleCompressionNumberInput = (key: CompressionField, event: Event) => {
|
const handleCompressionNumberInput = (key: CompressionField, event: Event) => {
|
||||||
const target = event.target as HTMLInputElement | null;
|
const target = event.target as HTMLInputElement | null;
|
||||||
if (!target || !target.value) {
|
if (!target || !target.value) {
|
||||||
|
|||||||
@ -17,6 +17,7 @@ interface PersonalForm {
|
|||||||
auto_generate_title: boolean;
|
auto_generate_title: boolean;
|
||||||
recent_conversations_prompt_enabled: boolean;
|
recent_conversations_prompt_enabled: boolean;
|
||||||
recent_conversations_prompt_limit: number | string;
|
recent_conversations_prompt_limit: number | string;
|
||||||
|
project_memory_inject_limit: number | string | null;
|
||||||
tool_intent_enabled: boolean;
|
tool_intent_enabled: boolean;
|
||||||
skill_hints_enabled: boolean;
|
skill_hints_enabled: boolean;
|
||||||
skill_strict_terminal_enabled: boolean;
|
skill_strict_terminal_enabled: boolean;
|
||||||
@ -94,11 +95,14 @@ interface PersonalizationState {
|
|||||||
toolCategories: Array<{ id: string; label: string }>;
|
toolCategories: Array<{ id: string; label: string }>;
|
||||||
skillsCatalog: Array<{ id: string; label: string; description?: string }>;
|
skillsCatalog: Array<{ id: string; label: string; description?: string }>;
|
||||||
recentConversationsPromptLimitRange: { min: number; max: number };
|
recentConversationsPromptLimitRange: { min: number; max: number };
|
||||||
|
projectMemoryInjectLimitMin: number;
|
||||||
experiments: ExperimentState;
|
experiments: ExperimentState;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_RECENT_CONVERSATIONS_PROMPT_LIMIT = 10;
|
const DEFAULT_RECENT_CONVERSATIONS_PROMPT_LIMIT = 10;
|
||||||
const DEFAULT_RECENT_CONVERSATIONS_PROMPT_LIMIT_RANGE = { min: 1, max: 30 };
|
const DEFAULT_RECENT_CONVERSATIONS_PROMPT_LIMIT_RANGE = { min: 1, max: 30 };
|
||||||
|
const DEFAULT_PROJECT_MEMORY_INJECT_LIMIT = 20;
|
||||||
|
const PROJECT_MEMORY_INJECT_LIMIT_MIN = 5;
|
||||||
const DEFAULT_SHALLOW_COMPRESS_TRIGGER_TOKENS = 80000;
|
const DEFAULT_SHALLOW_COMPRESS_TRIGGER_TOKENS = 80000;
|
||||||
const DEFAULT_DEEP_COMPRESS_TRIGGER_TOKENS = 150000;
|
const DEFAULT_DEEP_COMPRESS_TRIGGER_TOKENS = 150000;
|
||||||
const RUN_MODE_OPTIONS: RunMode[] = ['fast', 'thinking'];
|
const RUN_MODE_OPTIONS: RunMode[] = ['fast', 'thinking'];
|
||||||
@ -215,6 +219,7 @@ const defaultForm = (): PersonalForm => ({
|
|||||||
auto_generate_title: true,
|
auto_generate_title: true,
|
||||||
recent_conversations_prompt_enabled: false,
|
recent_conversations_prompt_enabled: false,
|
||||||
recent_conversations_prompt_limit: DEFAULT_RECENT_CONVERSATIONS_PROMPT_LIMIT,
|
recent_conversations_prompt_limit: DEFAULT_RECENT_CONVERSATIONS_PROMPT_LIMIT,
|
||||||
|
project_memory_inject_limit: DEFAULT_PROJECT_MEMORY_INJECT_LIMIT,
|
||||||
tool_intent_enabled: true,
|
tool_intent_enabled: true,
|
||||||
skill_hints_enabled: false,
|
skill_hints_enabled: false,
|
||||||
skill_strict_terminal_enabled: false,
|
skill_strict_terminal_enabled: false,
|
||||||
@ -338,6 +343,7 @@ export const usePersonalizationStore = defineStore('personalization', {
|
|||||||
toolCategories: [],
|
toolCategories: [],
|
||||||
skillsCatalog: [],
|
skillsCatalog: [],
|
||||||
recentConversationsPromptLimitRange: { ...DEFAULT_RECENT_CONVERSATIONS_PROMPT_LIMIT_RANGE },
|
recentConversationsPromptLimitRange: { ...DEFAULT_RECENT_CONVERSATIONS_PROMPT_LIMIT_RANGE },
|
||||||
|
projectMemoryInjectLimitMin: PROJECT_MEMORY_INJECT_LIMIT_MIN,
|
||||||
experiments: loadExperimentState()
|
experiments: loadExperimentState()
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
@ -419,6 +425,9 @@ export const usePersonalizationStore = defineStore('personalization', {
|
|||||||
recent_conversations_prompt_limit: this.normalizeRecentConversationsPromptLimit(
|
recent_conversations_prompt_limit: this.normalizeRecentConversationsPromptLimit(
|
||||||
data.recent_conversations_prompt_limit
|
data.recent_conversations_prompt_limit
|
||||||
),
|
),
|
||||||
|
project_memory_inject_limit: this.normalizeProjectMemoryInjectLimit(
|
||||||
|
data.project_memory_inject_limit
|
||||||
|
),
|
||||||
tool_intent_enabled: !!data.tool_intent_enabled,
|
tool_intent_enabled: !!data.tool_intent_enabled,
|
||||||
skill_hints_enabled: !!data.skill_hints_enabled,
|
skill_hints_enabled: !!data.skill_hints_enabled,
|
||||||
skill_strict_terminal_enabled: !!data.skill_strict_terminal_enabled,
|
skill_strict_terminal_enabled: !!data.skill_strict_terminal_enabled,
|
||||||
@ -604,6 +613,25 @@ export const usePersonalizationStore = defineStore('personalization', {
|
|||||||
}
|
}
|
||||||
return Math.max(min, Math.min(max, Math.round(parsed)));
|
return Math.max(min, Math.min(max, Math.round(parsed)));
|
||||||
},
|
},
|
||||||
|
normalizeProjectMemoryInjectLimit(value: any): number | null {
|
||||||
|
// undefined(老接口未下发)/非法值 → 默认 20;null/''/0/负数 → null(无上限);正整数钳到 >= min
|
||||||
|
if (typeof value === 'undefined') {
|
||||||
|
return DEFAULT_PROJECT_MEMORY_INJECT_LIMIT;
|
||||||
|
}
|
||||||
|
if (value === null || value === '') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const parsed = Number(value);
|
||||||
|
if (!Number.isFinite(parsed)) {
|
||||||
|
return DEFAULT_PROJECT_MEMORY_INJECT_LIMIT;
|
||||||
|
}
|
||||||
|
const rounded = Math.round(parsed);
|
||||||
|
if (rounded <= 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const min = this.projectMemoryInjectLimitMin ?? PROJECT_MEMORY_INJECT_LIMIT_MIN;
|
||||||
|
return Math.max(min, rounded);
|
||||||
|
},
|
||||||
applyPersonalizationMeta(payload: any) {
|
applyPersonalizationMeta(payload: any) {
|
||||||
if (payload && payload.recent_conversations_prompt_limit_range) {
|
if (payload && payload.recent_conversations_prompt_limit_range) {
|
||||||
const { min, max } = payload.recent_conversations_prompt_limit_range;
|
const { min, max } = payload.recent_conversations_prompt_limit_range;
|
||||||
@ -616,6 +644,13 @@ export const usePersonalizationStore = defineStore('personalization', {
|
|||||||
...DEFAULT_RECENT_CONVERSATIONS_PROMPT_LIMIT_RANGE
|
...DEFAULT_RECENT_CONVERSATIONS_PROMPT_LIMIT_RANGE
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (payload && payload.project_memory_inject_limit_range) {
|
||||||
|
const { min } = payload.project_memory_inject_limit_range;
|
||||||
|
this.projectMemoryInjectLimitMin =
|
||||||
|
typeof min === 'number' ? min : PROJECT_MEMORY_INJECT_LIMIT_MIN;
|
||||||
|
} else {
|
||||||
|
this.projectMemoryInjectLimitMin = PROJECT_MEMORY_INJECT_LIMIT_MIN;
|
||||||
|
}
|
||||||
if (payload && Array.isArray(payload.tool_categories)) {
|
if (payload && Array.isArray(payload.tool_categories)) {
|
||||||
this.toolCategories = payload.tool_categories
|
this.toolCategories = payload.tool_categories
|
||||||
.map((item: { id?: string; label?: string } = {}) => ({
|
.map((item: { id?: string; label?: string } = {}) => ({
|
||||||
@ -786,6 +821,27 @@ export const usePersonalizationStore = defineStore('personalization', {
|
|||||||
this.clearFeedback();
|
this.clearFeedback();
|
||||||
this.scheduleAutoSave();
|
this.scheduleAutoSave();
|
||||||
},
|
},
|
||||||
|
setProjectMemoryInjectLimit(value: number | null) {
|
||||||
|
// null = 无上限
|
||||||
|
const target =
|
||||||
|
value === null || typeof value === 'undefined'
|
||||||
|
? null
|
||||||
|
: this.normalizeProjectMemoryInjectLimit(value);
|
||||||
|
this.form = {
|
||||||
|
...this.form,
|
||||||
|
project_memory_inject_limit: target
|
||||||
|
};
|
||||||
|
this.clearFeedback();
|
||||||
|
this.scheduleAutoSave();
|
||||||
|
},
|
||||||
|
restoreProjectMemoryInjectLimit() {
|
||||||
|
this.form = {
|
||||||
|
...this.form,
|
||||||
|
project_memory_inject_limit: DEFAULT_PROJECT_MEMORY_INJECT_LIMIT
|
||||||
|
};
|
||||||
|
this.clearFeedback();
|
||||||
|
this.scheduleAutoSave();
|
||||||
|
},
|
||||||
toggleDefaultToolCategory(categoryId: string) {
|
toggleDefaultToolCategory(categoryId: string) {
|
||||||
if (!categoryId) {
|
if (!categoryId) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user