feat: virtual company module, team projects, PWA dishes app, and startup scripts overhaul
- Add company module (3-tier org, CEO planning, parallel departments) - Add company orchestrator, knowledge extractor, presets, scheduler - Add company API endpoints, models, and frontend views - Add 今天吃啥 PWA app (69 dishes, real images, offline support) - Add team_projects output directory structure - Add unified manage.ps1 for service lifecycle - Add Windows startup guide v1.0 - Add TTS troubleshooting doc - Update frontend (AgentChat UX overhaul, new views) - Update backend (voice engine fix, multi-tenant, RBAC) - Remove deprecated startup scripts and old docs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -136,8 +136,10 @@ class ChatRequest(BaseModel):
|
||||
message: str
|
||||
session_id: Optional[str] = None
|
||||
model: Optional[str] = None
|
||||
model_config_id: Optional[str] = Field(default=None, description="使用已保存的模型配置(含 API Key)")
|
||||
temperature: Optional[float] = None
|
||||
max_iterations: Optional[int] = None
|
||||
max_tokens: Optional[int] = Field(default=None, description="单次回复最大 token 数")
|
||||
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")
|
||||
@@ -355,17 +357,20 @@ async def chat_bare(
|
||||
"""无需 Agent 配置,使用默认设置直接对话。"""
|
||||
uid = current_user.id
|
||||
bare_scope = f"{uid}:__bare__" if uid else "__bare__"
|
||||
mc = _resolve_model_config(db, req.model_config_id, uid)
|
||||
llm_kwargs = _apply_model_config(dict(
|
||||
model=req.model or (
|
||||
"gpt-4o-mini" if settings.OPENAI_API_KEY and settings.OPENAI_API_KEY != "your-openai-api-key"
|
||||
else "deepseek-v4-flash"
|
||||
),
|
||||
temperature=req.temperature or 0.7,
|
||||
max_iterations=req.max_iterations or 10,
|
||||
max_tokens=req.max_tokens,
|
||||
), mc)
|
||||
config = AgentConfig(
|
||||
name="bare_agent",
|
||||
system_prompt="你是一个有用的AI助手。请使用可用工具来帮助用户完成任务。",
|
||||
llm=AgentLLMConfig(
|
||||
model=req.model or (
|
||||
"gpt-4o-mini" if settings.OPENAI_API_KEY and settings.OPENAI_API_KEY != "your-openai-api-key"
|
||||
else "deepseek-v4-flash"
|
||||
),
|
||||
temperature=req.temperature or 0.7,
|
||||
max_iterations=req.max_iterations or 10,
|
||||
),
|
||||
llm=AgentLLMConfig(**llm_kwargs),
|
||||
user_id=uid,
|
||||
memory_scope_id=bare_scope,
|
||||
memory=AgentMemoryConfig(
|
||||
@@ -421,17 +426,20 @@ async def chat_bare_stream(
|
||||
"""无需 Agent 配置,使用默认设置直接对话(流式 SSE)。"""
|
||||
uid = current_user.id
|
||||
bare_scope = f"{uid}:__bare__" if uid else "__bare__"
|
||||
mc = _resolve_model_config(db, req.model_config_id, uid)
|
||||
llm_kwargs = _apply_model_config(dict(
|
||||
model=req.model or (
|
||||
"gpt-4o-mini" if settings.OPENAI_API_KEY and settings.OPENAI_API_KEY != "your-openai-api-key"
|
||||
else "deepseek-v4-flash"
|
||||
),
|
||||
temperature=req.temperature or 0.7,
|
||||
max_iterations=req.max_iterations or 10,
|
||||
max_tokens=req.max_tokens,
|
||||
), mc)
|
||||
config = AgentConfig(
|
||||
name="bare_agent",
|
||||
system_prompt="你是一个有用的AI助手。请使用可用工具来帮助用户完成任务。",
|
||||
llm=AgentLLMConfig(
|
||||
model=req.model or (
|
||||
"gpt-4o-mini" if settings.OPENAI_API_KEY and settings.OPENAI_API_KEY != "your-openai-api-key"
|
||||
else "deepseek-v4-flash"
|
||||
),
|
||||
temperature=req.temperature or 0.7,
|
||||
max_iterations=req.max_iterations or 10,
|
||||
),
|
||||
llm=AgentLLMConfig(**llm_kwargs),
|
||||
user_id=uid,
|
||||
memory_scope_id=bare_scope,
|
||||
memory=AgentMemoryConfig(
|
||||
@@ -476,7 +484,7 @@ async def chat_with_agent(
|
||||
agent = db.query(Agent).filter(Agent.id == agent_id).first()
|
||||
if not agent:
|
||||
raise HTTPException(status_code=404, detail="Agent 不存在")
|
||||
if agent.user_id and agent.user_id != current_user.id and current_user.role != "admin" and not agent.is_public:
|
||||
if agent.user_id and agent.user_id != current_user.id and not current_user.has_permission("agent:chat_any") and not agent.is_public:
|
||||
raise HTTPException(status_code=403, detail="无权访问该 Agent")
|
||||
|
||||
# 从 Agent 配置构建 Runtime
|
||||
@@ -506,18 +514,20 @@ async def chat_with_agent(
|
||||
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
|
||||
mc = _resolve_model_config(db, req.model_config_id, uid)
|
||||
llm_kwargs = _apply_model_config(dict(
|
||||
provider=agent_node_cfg.get("provider", "openai"),
|
||||
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)),
|
||||
max_tokens=req.max_tokens or agent_node_cfg.get("max_tokens"),
|
||||
plan_mode_enabled=bool(agent_node_cfg.get("plan_mode_enabled", False)),
|
||||
plan_approval_required=bool(agent_node_cfg.get("plan_approval_required", True)),
|
||||
), mc)
|
||||
config = AgentConfig(
|
||||
name=agent.name,
|
||||
system_prompt=system_prompt,
|
||||
llm=AgentLLMConfig(
|
||||
provider=agent_node_cfg.get("provider", "openai"),
|
||||
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)),
|
||||
),
|
||||
llm=AgentLLMConfig(**llm_kwargs),
|
||||
tools=AgentToolConfig(
|
||||
include_tools=agent_node_cfg.get("tools", []),
|
||||
exclude_tools=agent_node_cfg.get("exclude_tools", []),
|
||||
@@ -577,7 +587,7 @@ async def chat_with_agent_stream(
|
||||
agent = db.query(Agent).filter(Agent.id == agent_id).first()
|
||||
if not agent:
|
||||
raise HTTPException(status_code=404, detail="Agent 不存在")
|
||||
if agent.user_id and agent.user_id != current_user.id and current_user.role != "admin" and not agent.is_public:
|
||||
if agent.user_id and agent.user_id != current_user.id and not current_user.has_permission("agent:chat_any") and not agent.is_public:
|
||||
raise HTTPException(status_code=403, detail="无权访问该 Agent")
|
||||
|
||||
wc = agent.workflow_config or {}
|
||||
@@ -603,18 +613,20 @@ async def chat_with_agent_stream(
|
||||
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
|
||||
mc = _resolve_model_config(db, req.model_config_id, uid)
|
||||
llm_kwargs = _apply_model_config(dict(
|
||||
provider=agent_node_cfg.get("provider", "openai"),
|
||||
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)),
|
||||
max_tokens=req.max_tokens or agent_node_cfg.get("max_tokens"),
|
||||
plan_mode_enabled=bool(agent_node_cfg.get("plan_mode_enabled", False)),
|
||||
plan_approval_required=bool(agent_node_cfg.get("plan_approval_required", True)),
|
||||
), mc)
|
||||
config = AgentConfig(
|
||||
name=agent.name,
|
||||
system_prompt=system_prompt,
|
||||
llm=AgentLLMConfig(
|
||||
provider=agent_node_cfg.get("provider", "openai"),
|
||||
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)),
|
||||
),
|
||||
llm=AgentLLMConfig(**llm_kwargs),
|
||||
tools=AgentToolConfig(
|
||||
include_tools=agent_node_cfg.get("tools", []),
|
||||
exclude_tools=agent_node_cfg.get("exclude_tools", []),
|
||||
@@ -901,7 +913,38 @@ async def search_messages(
|
||||
return SearchMessagesResponse(messages=result, total=total)
|
||||
|
||||
|
||||
def _find_agent_node_config(nodes: list) -> Dict[str, Any]:
|
||||
def _resolve_model_config(db: Session, model_config_id: Optional[str], user_id: str) -> Optional[Dict[str, Any]]:
|
||||
"""从数据库加载模型配置,返回 {provider, model, api_key, base_url}。"""
|
||||
if not model_config_id:
|
||||
return None
|
||||
from app.models.model_config import ModelConfig
|
||||
mc = db.query(ModelConfig).filter(
|
||||
ModelConfig.id == model_config_id,
|
||||
ModelConfig.user_id == user_id,
|
||||
).first()
|
||||
if not mc:
|
||||
raise HTTPException(status_code=404, detail="模型配置不存在")
|
||||
return {
|
||||
"provider": mc.provider,
|
||||
"model": mc.model_name,
|
||||
"api_key": mc.api_key,
|
||||
"base_url": mc.base_url,
|
||||
}
|
||||
|
||||
|
||||
def _apply_model_config(llm_kwargs: Dict[str, Any], mc: Optional[Dict[str, Any]]) -> Dict[str, Any]:
|
||||
"""将模型配置应用到 LLM 参数中。"""
|
||||
if not mc:
|
||||
return llm_kwargs
|
||||
if mc.get("provider"):
|
||||
llm_kwargs["provider"] = mc["provider"]
|
||||
if mc.get("model"):
|
||||
llm_kwargs["model"] = mc["model"]
|
||||
if mc.get("api_key"):
|
||||
llm_kwargs["api_key"] = mc["api_key"]
|
||||
if mc.get("base_url"):
|
||||
llm_kwargs["base_url"] = mc["base_url"]
|
||||
return llm_kwargs
|
||||
"""从工作流节点列表中查找第一个 agent 类型或 llm 类型的节点配置。"""
|
||||
if not nodes:
|
||||
return {}
|
||||
|
||||
Reference in New Issue
Block a user