fix: delete agent 500 error + dynamic personality + deployment guide

- Fix delete agent 500: clean up FK records (agent_llm_logs, permissions,
  schedules, executions, team_members) and unbind goals/tasks before delete
- Remove hardcoded personality templates in Android, replace with dynamic
  system prompt generation from name + description
- Set promptSectionsEnabled=false to bypass PromptComposer for personality
- Add Tencent Cloud Linux deployment guide (Docker Compose)
- Accumulated backend service updates, frontend UI fixes, Android app changes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-29 01:17:21 +08:00
parent 86b98865e3
commit beff3fac8d
1084 changed files with 117315 additions and 1281 deletions

View File

@@ -82,6 +82,9 @@ class ChatRequest(BaseModel):
model: Optional[str] = None
temperature: Optional[float] = None
max_iterations: Optional[int] = None
streamlined: bool = Field(default=False, description="启用工具结果流式美化")
prompt_sections_enabled: bool = Field(default=True, description="启用系统提示词分层装配")
system_prompt_override: Optional[str] = Field(default=None, description="覆盖 Agent 的 System Prompt")
class ChatResponse(BaseModel):
@@ -92,6 +95,8 @@ class ChatResponse(BaseModel):
session_id: str
agent_id: Optional[str] = None
steps: List[AgentStep] = Field(default_factory=list, description="执行追踪步骤")
streamlined_summary: Optional[str] = Field(default=None, description="流式美化摘要streamlined 模式)")
token_usage: Optional[Dict[str, Any]] = Field(default=None, description="Token 预算摘要")
class OrchestrateAgentItem(BaseModel):
@@ -249,11 +254,35 @@ async def chat_bare(
),
user_id=uid,
memory_scope_id=bare_scope,
memory=AgentMemoryConfig(
memory_dir_enabled=True,
memory_dir_path="",
persist_to_db=True,
vector_memory_enabled=True,
learning_enabled=True,
),
tools=AgentToolConfig(
permission_level="acceptEdits",
),
)
if not req.prompt_sections_enabled:
config.prompt_sections.enabled = False
if req.system_prompt_override:
config.system_prompt = req.system_prompt_override
on_llm_call = _make_llm_logger(db, agent_id=None, user_id=current_user.id)
runtime = AgentRuntime(config=config, on_llm_call=on_llm_call)
runtime = AgentRuntime(config=config, on_llm_call=on_llm_call, streamlined=req.streamlined)
result = await runtime.run(req.message)
# 流式美化:为 steps 生成累计摘要
streamlined_summary = None
if req.streamlined and result.steps:
from app.core.streamlined_output import ToolCounts, categorize_tool, get_tool_summary_text
counts = ToolCounts()
for s in result.steps:
if s.type == "tool_result" and s.tool_name:
counts.add(categorize_tool(s.tool_name))
streamlined_summary = get_tool_summary_text(counts)
return ChatResponse(
content=result.content,
iterations_used=result.iterations_used,
@@ -261,6 +290,8 @@ async def chat_bare(
truncated=result.truncated,
session_id=runtime.context.session_id,
steps=result.steps,
streamlined_summary=streamlined_summary,
token_usage=result.token_usage.model_dump() if result.token_usage else None,
)
@@ -286,9 +317,23 @@ async def chat_bare_stream(
),
user_id=uid,
memory_scope_id=bare_scope,
memory=AgentMemoryConfig(
memory_dir_enabled=True,
memory_dir_path="",
persist_to_db=True,
vector_memory_enabled=True,
learning_enabled=True,
),
tools=AgentToolConfig(
permission_level="acceptEdits",
),
)
if not req.prompt_sections_enabled:
config.prompt_sections.enabled = False
if req.system_prompt_override:
config.system_prompt = req.system_prompt_override
on_llm_call = _make_llm_logger(db, agent_id=None, user_id=current_user.id)
runtime = AgentRuntime(config=config, on_llm_call=on_llm_call)
runtime = AgentRuntime(config=config, on_llm_call=on_llm_call, streamlined=req.streamlined)
return StreamingResponse(
_sse_stream(runtime.run_stream(req.message)),
media_type="text/event-stream",
@@ -339,6 +384,8 @@ async def chat_with_agent(
uid = current_user.id
mem_scope = f"{uid}:{agent_id}" if uid else str(agent_id)
memory_cfg = _build_memory_config_from_node(agent_node_cfg)
if getattr(agent, "parent_agent_id", None):
memory_cfg.parent_agent_id = agent.parent_agent_id
config = AgentConfig(
name=agent.name,
system_prompt=system_prompt,
@@ -347,21 +394,42 @@ async def chat_with_agent(
model=req.model or agent_node_cfg.get("model", "gpt-4o-mini"),
temperature=req.temperature or float(agent_node_cfg.get("temperature", 0.7)),
max_iterations=req.max_iterations or int(agent_node_cfg.get("max_iterations", 10)),
# 计划模式 (P2)
plan_mode_enabled=bool(agent_node_cfg.get("plan_mode_enabled", False)),
plan_approval_required=bool(agent_node_cfg.get("plan_approval_required", True)),
),
tools=AgentToolConfig(
include_tools=agent_node_cfg.get("tools", []),
exclude_tools=agent_node_cfg.get("exclude_tools", []),
# 工具安全分级 (P3)
permission_level=str(agent_node_cfg.get("permission_level", "default")),
deny_tools=agent_node_cfg.get("deny_tools", []),
auto_approve_rules=agent_node_cfg.get("auto_approve_rules", []),
),
memory=memory_cfg,
budget=budget,
user_id=uid,
memory_scope_id=mem_scope,
)
if not req.prompt_sections_enabled:
config.prompt_sections.enabled = False
if req.system_prompt_override:
config.system_prompt = req.system_prompt_override
on_llm_call = _make_llm_logger(db, agent_id=agent_id, user_id=current_user.id)
runtime = AgentRuntime(config=config, on_llm_call=on_llm_call)
runtime = AgentRuntime(config=config, on_llm_call=on_llm_call, streamlined=req.streamlined)
result = await runtime.run(req.message)
# 流式美化:为 steps 生成累计摘要
streamlined_summary = None
if req.streamlined and result.steps:
from app.core.streamlined_output import ToolCounts, categorize_tool, get_tool_summary_text
counts = ToolCounts()
for s in result.steps:
if s.type == "tool_result" and s.tool_name:
counts.add(categorize_tool(s.tool_name))
streamlined_summary = get_tool_summary_text(counts)
return ChatResponse(
content=result.content,
iterations_used=result.iterations_used,
@@ -370,6 +438,8 @@ async def chat_with_agent(
session_id=runtime.context.session_id,
agent_id=agent_id,
steps=result.steps,
streamlined_summary=streamlined_summary,
token_usage=result.token_usage.model_dump() if result.token_usage else None,
)
@@ -408,6 +478,8 @@ async def chat_with_agent_stream(
uid = current_user.id
mem_scope = f"{uid}:{agent_id}" if uid else str(agent_id)
memory_cfg = _build_memory_config_from_node(agent_node_cfg)
if getattr(agent, "parent_agent_id", None):
memory_cfg.parent_agent_id = agent.parent_agent_id
config = AgentConfig(
name=agent.name,
system_prompt=system_prompt,
@@ -416,19 +488,30 @@ async def chat_with_agent_stream(
model=req.model or agent_node_cfg.get("model", "gpt-4o-mini"),
temperature=req.temperature or float(agent_node_cfg.get("temperature", 0.7)),
max_iterations=req.max_iterations or int(agent_node_cfg.get("max_iterations", 10)),
# 计划模式 (P2)
plan_mode_enabled=bool(agent_node_cfg.get("plan_mode_enabled", False)),
plan_approval_required=bool(agent_node_cfg.get("plan_approval_required", True)),
),
tools=AgentToolConfig(
include_tools=agent_node_cfg.get("tools", []),
exclude_tools=agent_node_cfg.get("exclude_tools", []),
# 工具安全分级 (P3)
permission_level=str(agent_node_cfg.get("permission_level", "default")),
deny_tools=agent_node_cfg.get("deny_tools", []),
auto_approve_rules=agent_node_cfg.get("auto_approve_rules", []),
),
memory=memory_cfg,
budget=budget,
user_id=uid,
memory_scope_id=mem_scope,
)
if not req.prompt_sections_enabled:
config.prompt_sections.enabled = False
if req.system_prompt_override:
config.system_prompt = req.system_prompt_override
on_llm_call = _make_llm_logger(db, agent_id=agent_id, user_id=current_user.id)
runtime = AgentRuntime(config=config, on_llm_call=on_llm_call)
runtime = AgentRuntime(config=config, on_llm_call=on_llm_call, streamlined=req.streamlined)
return StreamingResponse(
_sse_stream(runtime.run_stream(req.message)),
media_type="text/event-stream",
@@ -453,10 +536,24 @@ def _find_agent_node_config(nodes: list) -> Dict[str, Any]:
def _build_memory_config_from_node(agent_node_cfg: dict) -> AgentMemoryConfig:
"""从 Agent 工作流节点配置中提取记忆配置。"""
from app.core.compaction_config import CompactionConfig
# 压缩配置
compaction_raw = agent_node_cfg.get("compaction")
if isinstance(compaction_raw, dict):
compaction = CompactionConfig(**compaction_raw)
else:
compaction = CompactionConfig() # 默认配置
return AgentMemoryConfig(
max_history_messages=int(agent_node_cfg.get("memory_max_history", 20)),
vector_memory_top_k=int(agent_node_cfg.get("memory_vector_top_k", 5)),
persist_to_db=bool(agent_node_cfg.get("memory_persist", True)),
vector_memory_enabled=bool(agent_node_cfg.get("memory_vector_enabled", True)),
learning_enabled=bool(agent_node_cfg.get("memory_learning", True)),
# 文件式记忆 (MEMORY.md)
memory_dir_enabled=bool(agent_node_cfg.get("memory_dir_enabled", False)),
memory_dir_path=str(agent_node_cfg.get("memory_dir_path", "")),
# 对话压缩
compaction=compaction,
)