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:
@@ -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,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user