Merge branch 'develop-mark' into develop
This commit is contained in:
@@ -674,7 +674,8 @@ async def draft_run_compare(
|
||||
workspace_id=workspace_id,
|
||||
user=current_user
|
||||
)
|
||||
if storage_type is None: storage_type = 'neo4j'
|
||||
if storage_type is None:
|
||||
storage_type = 'neo4j'
|
||||
user_rag_memory_id = ''
|
||||
if workspace_id:
|
||||
knowledge = knowledge_repository.get_knowledge_by_name(
|
||||
@@ -682,7 +683,8 @@ async def draft_run_compare(
|
||||
name="USER_RAG_MERORY",
|
||||
workspace_id=workspace_id
|
||||
)
|
||||
if knowledge: user_rag_memory_id = str(knowledge.id)
|
||||
if knowledge:
|
||||
user_rag_memory_id = str(knowledge.id)
|
||||
|
||||
logger.info(
|
||||
"多模型对比试运行",
|
||||
|
||||
@@ -1,31 +1,23 @@
|
||||
from fastapi import APIRouter, Depends, Query, Request, Header
|
||||
import hashlib
|
||||
import uuid
|
||||
|
||||
from fastapi import APIRouter, Depends, Query, Request
|
||||
from fastapi.responses import StreamingResponse
|
||||
from sqlalchemy.orm import Session
|
||||
import uuid
|
||||
import hashlib
|
||||
import time
|
||||
import jwt
|
||||
from app.services import task_service, workspace_service
|
||||
from typing import Optional, Dict
|
||||
from functools import wraps
|
||||
from app.dependencies import get_current_superuser, get_current_user, get_current_tenant, workspace_access_guard, cur_workspace_access_guard
|
||||
from app.db import get_db
|
||||
from app.core.response_utils import success
|
||||
|
||||
from app.core.logging_config import get_business_logger
|
||||
from app.core.exceptions import BusinessException
|
||||
from app.core.error_codes import BizCode
|
||||
from app.core.config import settings
|
||||
from app.core.response_utils import success
|
||||
from app.db import get_db
|
||||
from app.dependencies import get_share_user_id, ShareTokenData
|
||||
from app.repositories import knowledge_repository
|
||||
from app.schemas import release_share_schema, conversation_schema
|
||||
from app.schemas.response_schema import PageData, PageMeta
|
||||
from app.services import workspace_service
|
||||
from app.services.auth_service import create_access_token
|
||||
from app.services.conversation_service import ConversationService
|
||||
from app.services.release_share_service import ReleaseShareService
|
||||
from app.services.shared_chat_service import SharedChatService
|
||||
from app.services.conversation_service import ConversationService
|
||||
from app.services.auth_service import create_access_token
|
||||
from app.dependencies import get_share_user_id, ShareTokenData
|
||||
from app.models.user_model import User
|
||||
from app.repositories.app_repository import AppRepository
|
||||
from app.repositories.workspace_repository import WorkspaceRepository
|
||||
from app.repositories import knowledge_repository
|
||||
|
||||
router = APIRouter(prefix="/public/share", tags=["Public Share"])
|
||||
logger = get_business_logger()
|
||||
|
||||
@@ -37,31 +29,31 @@ def get_base_url(request: Request) -> str:
|
||||
|
||||
def get_or_generate_user_id(payload_user_id: str, request: Request) -> str:
|
||||
"""获取或生成用户 ID
|
||||
|
||||
|
||||
优先级:
|
||||
1. 使用前端传递的 user_id
|
||||
2. 基于 IP + User-Agent 生成唯一 ID
|
||||
|
||||
|
||||
Args:
|
||||
payload_user_id: 前端传递的 user_id
|
||||
request: FastAPI Request 对象
|
||||
|
||||
|
||||
Returns:
|
||||
用户 ID
|
||||
"""
|
||||
if payload_user_id:
|
||||
return payload_user_id
|
||||
|
||||
|
||||
# 获取客户端 IP
|
||||
client_ip = request.client.host if request.client else "unknown"
|
||||
|
||||
|
||||
# 获取 User-Agent
|
||||
user_agent = request.headers.get("user-agent", "unknown")
|
||||
|
||||
|
||||
# 生成唯一 ID:基于 IP + User-Agent 的哈希
|
||||
unique_string = f"{client_ip}_{user_agent}"
|
||||
hash_value = hashlib.md5(unique_string.encode()).hexdigest()[:16]
|
||||
|
||||
|
||||
return f"guest_{hash_value}"
|
||||
|
||||
|
||||
@@ -76,13 +68,13 @@ def get_access_token(
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""获取访问 token
|
||||
|
||||
|
||||
- 用户通过 user_id + share_token 换取访问 token
|
||||
- 后续请求需要携带此 token
|
||||
"""
|
||||
# 获取或生成 user_id
|
||||
user_id = get_or_generate_user_id(payload.user_id, request)
|
||||
|
||||
|
||||
# 验证分享链接(可选:验证密码)
|
||||
service = ReleaseShareService(db)
|
||||
try:
|
||||
@@ -93,10 +85,10 @@ def get_access_token(
|
||||
except Exception as e:
|
||||
logger.error(f"获取分享信息失败: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
# 生成 token
|
||||
access_token = create_access_token(user_id, share_token)
|
||||
|
||||
|
||||
logger.info(
|
||||
"生成访问 token",
|
||||
extra={
|
||||
@@ -104,7 +96,7 @@ def get_access_token(
|
||||
"user_id": user_id
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
return success(data={
|
||||
"access_token": access_token,
|
||||
"token_type": "Bearer",
|
||||
@@ -123,7 +115,7 @@ def get_shared_release(
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""获取公开分享的发布版本信息
|
||||
|
||||
|
||||
- 无需认证即可访问
|
||||
- 如果设置了密码保护,需要提供正确的密码
|
||||
- 如果密码错误或未提供密码,返回基本信息(不含配置详情)
|
||||
@@ -133,7 +125,7 @@ def get_shared_release(
|
||||
share_token=share_data.share_token,
|
||||
password=password
|
||||
)
|
||||
|
||||
|
||||
return success(data=info)
|
||||
|
||||
|
||||
@@ -147,7 +139,7 @@ def verify_password(
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""验证分享的访问密码
|
||||
|
||||
|
||||
- 用于前端先验证密码,再获取完整信息
|
||||
"""
|
||||
service = ReleaseShareService(db)
|
||||
@@ -155,7 +147,7 @@ def verify_password(
|
||||
share_token=share_data.share_token,
|
||||
password=payload.password
|
||||
)
|
||||
|
||||
|
||||
return success(data={"valid": is_valid})
|
||||
|
||||
|
||||
@@ -163,7 +155,7 @@ def verify_password(
|
||||
"/embed",
|
||||
summary="获取嵌入代码"
|
||||
)
|
||||
def get_embed_code(
|
||||
def get_embed_code(
|
||||
width: str = Query("100%", description="iframe 宽度"),
|
||||
height: str = Query("600px", description="iframe 高度"),
|
||||
request: Request = None,
|
||||
@@ -171,12 +163,12 @@ def get_embed_code(
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""获取嵌入代码
|
||||
|
||||
|
||||
- 返回 iframe 嵌入代码
|
||||
- 可以自定义宽度和高度
|
||||
"""
|
||||
base_url = get_base_url(request) if request else None
|
||||
|
||||
|
||||
service = ReleaseShareService(db)
|
||||
embed_code = service.get_embed_code(
|
||||
share_token=share_data.share_token,
|
||||
@@ -184,7 +176,7 @@ def get_embed_code(
|
||||
height=height,
|
||||
base_url=base_url
|
||||
)
|
||||
|
||||
|
||||
return success(data=embed_code)
|
||||
|
||||
|
||||
@@ -203,7 +195,7 @@ def list_conversations(
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""获取分享应用的会话列表
|
||||
|
||||
|
||||
- 可以按 user_id 筛选
|
||||
- 支持分页
|
||||
"""
|
||||
@@ -214,7 +206,7 @@ def list_conversations(
|
||||
from app.repositories.end_user_repository import EndUserRepository
|
||||
end_user_repo = EndUserRepository(db)
|
||||
new_end_user = end_user_repo.get_or_create_end_user(
|
||||
app_id=share.app_id,
|
||||
app_id=share.app_id,
|
||||
other_id=other_id
|
||||
)
|
||||
logger.debug(new_end_user.id)
|
||||
@@ -226,10 +218,10 @@ def list_conversations(
|
||||
page=page,
|
||||
pagesize=pagesize
|
||||
)
|
||||
|
||||
|
||||
items = [conversation_schema.Conversation.model_validate(c) for c in conversations]
|
||||
meta = PageMeta(page=page, pagesize=pagesize, total=total, hasnext=(page * pagesize) < total)
|
||||
|
||||
|
||||
return success(data=PageData(page=meta, items=items))
|
||||
|
||||
|
||||
@@ -250,17 +242,17 @@ def get_conversation(
|
||||
conversation_id=conversation_id,
|
||||
password=password
|
||||
)
|
||||
|
||||
|
||||
# 获取消息
|
||||
conv_service = ConversationService(db)
|
||||
messages = conv_service.get_messages(conversation_id)
|
||||
|
||||
|
||||
# 构建响应
|
||||
conv_dict = conversation_schema.Conversation.model_validate(conversation).model_dump()
|
||||
conv_dict["messages"] = [
|
||||
conversation_schema.Message.model_validate(m) for m in messages
|
||||
]
|
||||
|
||||
|
||||
return success(data=conv_dict)
|
||||
|
||||
|
||||
@@ -276,17 +268,17 @@ async def chat(
|
||||
db: Session = Depends(get_db)
|
||||
):
|
||||
"""发送消息并获取回复
|
||||
|
||||
|
||||
使用 Bearer token 认证:
|
||||
- Header: Authorization: Bearer {token}
|
||||
- user_id 和 share_token 从 token 中解码
|
||||
|
||||
|
||||
- 支持多轮对话(提供 conversation_id)
|
||||
- 支持流式返回(设置 stream=true)
|
||||
- 如果不提供 conversation_id,会自动创建新会话
|
||||
"""
|
||||
service = SharedChatService(db)
|
||||
|
||||
|
||||
# 从依赖中获取 user_id 和 share_token
|
||||
user_id = share_data.user_id
|
||||
share_token = share_data.share_token
|
||||
@@ -299,19 +291,19 @@ async def chat(
|
||||
from app.models.app_model import AppType
|
||||
try:
|
||||
from app.core.exceptions import BusinessException
|
||||
from app.core.error_codes import BizCode
|
||||
from app.core.error_codes import BizCode
|
||||
from app.services.app_service import AppService
|
||||
# 验证分享链接和密码
|
||||
share, release = service._get_release_by_share_token(share_token, password)
|
||||
|
||||
|
||||
# # Create end_user_id by concatenating app_id with user_id
|
||||
# end_user_id = f"{share.app_id}_{user_id}"
|
||||
|
||||
|
||||
# Store end_user_id in database with original user_id
|
||||
from app.repositories.end_user_repository import EndUserRepository
|
||||
end_user_repo = EndUserRepository(db)
|
||||
new_end_user = end_user_repo.get_or_create_end_user(
|
||||
app_id=share.app_id,
|
||||
app_id=share.app_id,
|
||||
other_id=other_id,
|
||||
original_user_id=user_id # Save original user_id to other_id
|
||||
)
|
||||
@@ -319,21 +311,21 @@ async def chat(
|
||||
|
||||
appid=share.app_id
|
||||
"""获取存储类型和工作空间的ID"""
|
||||
|
||||
|
||||
# 直接通过 SQLAlchemy 查询 app
|
||||
from app.models.app_model import App
|
||||
app = db.query(App).filter(App.id == appid).first()
|
||||
if not app:
|
||||
raise BusinessException("应用不存在", BizCode.APP_NOT_FOUND)
|
||||
|
||||
|
||||
workspace_id = app.workspace_id
|
||||
|
||||
|
||||
# 直接从 workspace 获取 storage_type(公开分享场景无需权限检查)
|
||||
storage_type = workspace_service.get_workspace_storage_type_without_auth(
|
||||
db=db,
|
||||
workspace_id=workspace_id
|
||||
)
|
||||
if storage_type is None:
|
||||
if storage_type is None:
|
||||
storage_type = 'neo4j'
|
||||
user_rag_memory_id = ''
|
||||
|
||||
@@ -357,7 +349,7 @@ async def chat(
|
||||
|
||||
# 获取应用类型
|
||||
app_type = release.app.type if release.app else None
|
||||
|
||||
|
||||
# 根据应用类型验证配置
|
||||
if app_type == "agent":
|
||||
# Agent 类型:验证模型配置
|
||||
@@ -371,7 +363,7 @@ async def chat(
|
||||
raise BusinessException("多 Agent 应用未配置子 Agent", BizCode.AGENT_CONFIG_MISSING)
|
||||
else:
|
||||
raise BusinessException(f"不支持的应用类型: {app_type}", BizCode.APP_TYPE_NOT_SUPPORTED)
|
||||
|
||||
|
||||
# 获取或创建会话(提前验证)
|
||||
conversation = service.create_or_get_conversation(
|
||||
share_token=share_data.share_token,
|
||||
@@ -379,7 +371,7 @@ async def chat(
|
||||
user_id=str(new_end_user.id), # 转换为字符串
|
||||
password=password
|
||||
)
|
||||
|
||||
|
||||
logger.debug(
|
||||
"参数验证完成",
|
||||
extra={
|
||||
@@ -389,12 +381,12 @@ async def chat(
|
||||
"stream": payload.stream
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
# 验证失败,直接抛出异常(会被 FastAPI 的异常处理器捕获)
|
||||
logger.error(f"参数验证失败: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
if app_type == AppType.AGENT:
|
||||
# 流式返回
|
||||
if payload.stream:
|
||||
@@ -412,7 +404,7 @@ async def chat(
|
||||
user_rag_memory_id=user_rag_memory_id
|
||||
):
|
||||
yield event
|
||||
|
||||
|
||||
return StreamingResponse(
|
||||
event_generator(),
|
||||
media_type="text/event-stream",
|
||||
@@ -422,7 +414,7 @@ async def chat(
|
||||
"X-Accel-Buffering": "no"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
# 非流式返回
|
||||
result = await service.chat(
|
||||
share_token=share_token,
|
||||
@@ -454,7 +446,7 @@ async def chat(
|
||||
user_rag_memory_id=user_rag_memory_id
|
||||
):
|
||||
yield event
|
||||
|
||||
|
||||
return StreamingResponse(
|
||||
event_generator(),
|
||||
media_type="text/event-stream",
|
||||
@@ -464,7 +456,7 @@ async def chat(
|
||||
"X-Accel-Buffering": "no"
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
# 多 Agent 非流式返回
|
||||
result = await service.multi_agent_chat(
|
||||
share_token=share_token,
|
||||
@@ -478,7 +470,7 @@ async def chat(
|
||||
storage_type=storage_type,
|
||||
user_rag_memory_id=user_rag_memory_id
|
||||
)
|
||||
|
||||
|
||||
return success(data=conversation_schema.ChatResponse(**result))
|
||||
else:
|
||||
from app.core.exceptions import BusinessException
|
||||
|
||||
@@ -1,30 +1,28 @@
|
||||
"""App 服务接口 - 基于 API Key 认证"""
|
||||
import uuid
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, Depends, Request, Body
|
||||
from sqlalchemy.orm import Session
|
||||
from typing import Optional, Annotated
|
||||
|
||||
from starlette.responses import StreamingResponse
|
||||
|
||||
from app.core.api_key_auth import require_api_key
|
||||
from app.db import get_db
|
||||
from app.core.response_utils import success
|
||||
from app.core.error_codes import BizCode
|
||||
from app.core.exceptions import BusinessException
|
||||
from app.core.logging_config import get_business_logger
|
||||
from app.core.response_utils import success
|
||||
from app.db import get_db
|
||||
from app.dependencies import get_app_or_workspace
|
||||
from app.models import AppRelease
|
||||
from app.repositories import knowledge_repository
|
||||
from app.schemas import AppChatRequest, conversation_schema
|
||||
from app.models.app_model import App
|
||||
from app.models.app_model import AppType
|
||||
from app.repositories import knowledge_repository
|
||||
from app.repositories.end_user_repository import EndUserRepository
|
||||
from app.core.exceptions import BusinessException
|
||||
from app.core.error_codes import BizCode
|
||||
from app.schemas import AppChatRequest, conversation_schema
|
||||
from app.schemas.api_key_schema import ApiKeyAuth
|
||||
from app.services import workspace_service
|
||||
from app.services.app_chat_service import AppChatService, get_app_chat_service
|
||||
from app.services.app_service import AppService
|
||||
from app.services.conversation_service import ConversationService, get_conversation_service
|
||||
from app.services.workflow_service import WorkflowService, get_workflow_service
|
||||
from app.utils.app_config_utils import dict_to_multi_agent_config,dict_to_workflow_config,agent_config_4_app_release
|
||||
from app.utils.app_config_utils import dict_to_multi_agent_config, dict_to_workflow_config, agent_config_4_app_release
|
||||
from app.services.app_service import get_app_service, AppService
|
||||
|
||||
router = APIRouter(prefix="/app", tags=["V1 - App API"])
|
||||
logger = get_business_logger()
|
||||
@@ -37,8 +35,9 @@ async def list_apps():
|
||||
|
||||
# /v1/apps/{resource_id}/chat
|
||||
|
||||
|
||||
# async def chat(
|
||||
# @router.post("/chat")
|
||||
# @require_api_key(scopes=["app"])
|
||||
# async def chat2(
|
||||
# request: Request,
|
||||
# api_key_auth: ApiKeyAuth = None,
|
||||
# db: Session = Depends(get_db),
|
||||
@@ -57,7 +56,6 @@ async def list_apps():
|
||||
# db: db_session
|
||||
# """
|
||||
# logger.info(f"API Key Auth: {api_key_auth}")
|
||||
# logger.info(f"Resource ID: {resource_id}")
|
||||
# logger.info(f"Message: {message}")
|
||||
# return success(data={"received": True}, msg="消息已接收")
|
||||
|
||||
@@ -76,15 +74,21 @@ def _checkAppConfig(app: App):
|
||||
raise BusinessException("不支持的应用类型", BizCode.AGENT_CONFIG_MISSING)
|
||||
|
||||
@router.post("/chat")
|
||||
# @require_api_key(scopes=["app"])
|
||||
@require_api_key(scopes=["app"])
|
||||
async def chat(
|
||||
payload: AppChatRequest,
|
||||
app: App = Depends(get_app_or_workspace),
|
||||
request:Request,
|
||||
api_key_auth: ApiKeyAuth = None,
|
||||
db: Session = Depends(get_db),
|
||||
conversation_service: Annotated[ConversationService, Depends(get_conversation_service)] = None,
|
||||
app_chat_service: Annotated[AppChatService, Depends(get_app_chat_service)] = None,
|
||||
|
||||
app_service: Annotated[AppService, Depends(get_app_service)] = None,
|
||||
message: str = Body(..., description="聊天消息内容"),
|
||||
):
|
||||
body = await request.json()
|
||||
payload = AppChatRequest(**body)
|
||||
|
||||
other_id = payload.user_id
|
||||
app = app_service.get_app(api_key_auth.resource_id, api_key_auth.workspace_id)
|
||||
other_id = payload.user_id
|
||||
workspace_id = app.workspace_id
|
||||
end_user_repo = EndUserRepository(db)
|
||||
@@ -176,7 +180,7 @@ async def chat(
|
||||
storage_type=storage_type,
|
||||
user_rag_memory_id=user_rag_memory_id
|
||||
)
|
||||
return success(data=conversation_schema.ChatResponse(**result))
|
||||
return success(data=conversation_schema.ChatResponse(**result).model_dump(mode="json"))
|
||||
elif app_type == AppType.MULTI_AGENT:
|
||||
# 多 Agent 流式返回
|
||||
config = dict_to_multi_agent_config(app.current_release.config,app.id)
|
||||
@@ -220,7 +224,7 @@ async def chat(
|
||||
user_rag_memory_id=user_rag_memory_id
|
||||
)
|
||||
|
||||
return success(data=conversation_schema.ChatResponse(**result))
|
||||
return success(data=conversation_schema.ChatResponse(**result).model_dump(mode="json"))
|
||||
elif app_type == AppType.WORKFLOW:
|
||||
# 多 Agent 流式返回
|
||||
config = dict_to_workflow_config(app.current_release.config,app.id)
|
||||
@@ -264,7 +268,7 @@ async def chat(
|
||||
user_rag_memory_id=user_rag_memory_id
|
||||
)
|
||||
|
||||
return success(data=conversation_schema.ChatResponse(**result))
|
||||
return success(data=conversation_schema.ChatResponse(**result).model_dump(mode="json"))
|
||||
else:
|
||||
from app.core.exceptions import BusinessException
|
||||
from app.core.error_codes import BizCode
|
||||
|
||||
@@ -1,26 +1,42 @@
|
||||
"""多 Agent 相关数据模型"""
|
||||
import datetime
|
||||
import uuid
|
||||
from enum import StrEnum
|
||||
|
||||
from sqlalchemy import Column, String, Boolean, DateTime, Integer, Float, Text, ForeignKey
|
||||
from sqlalchemy.dialects.postgresql import UUID, JSON
|
||||
from sqlalchemy.orm import relationship
|
||||
|
||||
from app.db import Base
|
||||
|
||||
class OrchestrationMode(StrEnum):
|
||||
"""图标类型枚举"""
|
||||
SEQUENTIAL = "sequential"
|
||||
PARALLEL = "parallel"
|
||||
CONDITIONAL = "conditional"
|
||||
|
||||
class AggregationStrategy(StrEnum):
|
||||
"""图标类型枚举"""
|
||||
MERGE = "merge"
|
||||
VOTE = "vote"
|
||||
PRIORITY = "priority"
|
||||
|
||||
class MultiAgentConfig(Base):
|
||||
"""多 Agent 配置表"""
|
||||
__tablename__ = "multi_agent_configs"
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
|
||||
|
||||
|
||||
# 关联应用
|
||||
app_id = Column(UUID(as_uuid=True), ForeignKey("apps.id"), nullable=False, unique=True, index=True, comment="关联应用")
|
||||
|
||||
|
||||
# 主 Agent (存储发布版本 ID)
|
||||
master_agent_id = Column(UUID(as_uuid=True), ForeignKey("app_releases.id"), nullable=False, comment="主 Agent 发布版本 ID")
|
||||
master_agent_id = Column(UUID(as_uuid=True), ForeignKey("app_releases.id"), nullable=True, comment="主 Agent 发布版本 ID")
|
||||
master_agent_name = Column(String(100), comment="主 Agent 名称")
|
||||
|
||||
|
||||
default_model_config_id = Column(UUID(as_uuid=True), ForeignKey("model_configs.id"), nullable=False,server_default=str(uuid.UUID(int=0)), index=True, comment="默认模型配置ID")
|
||||
# 结构化配置(直接存储 JSON)
|
||||
model_parameters = Column(JSON, nullable=True, comment="模型参数配置(temperature、max_tokens等)")
|
||||
# 协作模式
|
||||
orchestration_mode = Column(
|
||||
String(20),
|
||||
@@ -28,7 +44,7 @@ class MultiAgentConfig(Base):
|
||||
default="conditional",
|
||||
comment="协作模式: sequential|parallel|conditional|loop"
|
||||
)
|
||||
|
||||
|
||||
# 子 Agent 列表
|
||||
sub_agents = Column(
|
||||
JSON,
|
||||
@@ -36,13 +52,13 @@ class MultiAgentConfig(Base):
|
||||
default=list,
|
||||
comment="子 Agent 列表: [{'agent_id': 'uuid', 'name': '...', 'role': '...', 'priority': 1}]"
|
||||
)
|
||||
|
||||
|
||||
# 路由规则
|
||||
routing_rules = Column(
|
||||
JSON,
|
||||
comment="路由规则: [{'condition': '...', 'target_agent_id': 'uuid', 'priority': 1}]"
|
||||
)
|
||||
|
||||
|
||||
# 执行配置
|
||||
execution_config = Column(
|
||||
JSON,
|
||||
@@ -50,7 +66,7 @@ class MultiAgentConfig(Base):
|
||||
default=dict,
|
||||
comment="执行配置: {'max_iterations': 5, 'timeout': 60, 'parallel_limit': 3}"
|
||||
)
|
||||
|
||||
|
||||
# 结果整合策略
|
||||
aggregation_strategy = Column(
|
||||
String(20),
|
||||
@@ -58,12 +74,12 @@ class MultiAgentConfig(Base):
|
||||
default="merge",
|
||||
comment="结果整合策略: merge|vote|priority|custom"
|
||||
)
|
||||
|
||||
|
||||
# 状态
|
||||
is_active = Column(Boolean, default=True, nullable=False)
|
||||
created_at = Column(DateTime, default=datetime.datetime.now)
|
||||
updated_at = Column(DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now)
|
||||
|
||||
|
||||
# 关系
|
||||
app = relationship("App")
|
||||
master_agent_release = relationship("AppRelease", foreign_keys=[master_agent_id])
|
||||
@@ -77,7 +93,7 @@ class AgentInvocation(Base):
|
||||
__tablename__ = "agent_invocations"
|
||||
|
||||
id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True)
|
||||
|
||||
|
||||
# 调用关系
|
||||
caller_agent_id = Column(
|
||||
UUID(as_uuid=True),
|
||||
@@ -93,7 +109,7 @@ class AgentInvocation(Base):
|
||||
index=True,
|
||||
comment="被调用者 Agent ID"
|
||||
)
|
||||
|
||||
|
||||
# 关联信息
|
||||
conversation_id = Column(
|
||||
UUID(as_uuid=True),
|
||||
@@ -106,12 +122,12 @@ class AgentInvocation(Base):
|
||||
index=True,
|
||||
comment="父调用 ID(用于追踪调用链)"
|
||||
)
|
||||
|
||||
|
||||
# 输入输出
|
||||
input_message = Column(Text, nullable=False, comment="输入消息")
|
||||
output_message = Column(Text, comment="输出消息")
|
||||
context = Column(JSON, comment="上下文信息")
|
||||
|
||||
|
||||
# 状态
|
||||
status = Column(
|
||||
String(20),
|
||||
@@ -121,18 +137,18 @@ class AgentInvocation(Base):
|
||||
comment="状态: pending|running|completed|failed"
|
||||
)
|
||||
error_message = Column(Text, comment="错误信息")
|
||||
|
||||
|
||||
# 性能指标
|
||||
started_at = Column(DateTime, nullable=False, default=datetime.datetime.now, index=True)
|
||||
completed_at = Column(DateTime)
|
||||
elapsed_time = Column(Float, comment="耗时(秒)")
|
||||
token_usage = Column(JSON, comment="Token 使用情况")
|
||||
|
||||
|
||||
# 元数据
|
||||
meta_data = Column(JSON, comment="额外元数据")
|
||||
|
||||
|
||||
created_at = Column(DateTime, default=datetime.datetime.now)
|
||||
|
||||
|
||||
# 关系
|
||||
caller = relationship("AgentConfig", foreign_keys=[caller_agent_id])
|
||||
callee = relationship("AgentConfig", foreign_keys=[callee_agent_id])
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
"""
|
||||
import datetime
|
||||
import uuid
|
||||
from typing import Optional, List, Dict, Any, Tuple, Type
|
||||
from typing import Optional, List, Dict, Any, Tuple, Annotated
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlalchemy import select, func, or_, and_
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -20,6 +21,7 @@ from app.core.exceptions import (
|
||||
BusinessException,
|
||||
)
|
||||
from app.core.logging_config import get_business_logger
|
||||
from app.db import get_db
|
||||
from app.models import App, AgentConfig, AppRelease, MultiAgentConfig, WorkflowConfig
|
||||
from app.models.app_model import AppStatus, AppType
|
||||
from app.repositories.app_repository import get_apps_by_id
|
||||
@@ -27,6 +29,7 @@ from app.repositories.workflow_repository import WorkflowConfigRepository
|
||||
from app.schemas import app_schema
|
||||
from app.schemas.workflow_schema import WorkflowConfigUpdate
|
||||
from app.services.agent_config_converter import AgentConfigConverter
|
||||
from app.models import AppShare, Workspace
|
||||
|
||||
# 获取业务日志器
|
||||
logger = get_business_logger()
|
||||
@@ -1390,7 +1393,7 @@ class AppService:
|
||||
target_workspace_ids: List[uuid.UUID],
|
||||
user_id: uuid.UUID,
|
||||
workspace_id: Optional[uuid.UUID] = None
|
||||
) -> List["AppShare"]:
|
||||
) -> AppShare:
|
||||
"""分享应用到其他工作空间
|
||||
|
||||
Args:
|
||||
@@ -1406,7 +1409,7 @@ class AppService:
|
||||
ResourceNotFoundException: 当应用不存在时
|
||||
BusinessException: 当应用不在指定工作空间或目标工作空间无效时
|
||||
"""
|
||||
from app.models import AppShare, Workspace
|
||||
|
||||
|
||||
logger.info(
|
||||
"分享应用",
|
||||
@@ -1548,7 +1551,7 @@ class AppService:
|
||||
*,
|
||||
app_id: uuid.UUID,
|
||||
workspace_id: Optional[uuid.UUID] = None
|
||||
) -> List["AppShare"]:
|
||||
) -> List[AppShare]:
|
||||
"""列出应用的所有分享记录
|
||||
|
||||
Args:
|
||||
@@ -2094,3 +2097,14 @@ async def draft_run_stream(
|
||||
workspace_id=workspace_id
|
||||
):
|
||||
yield event
|
||||
|
||||
|
||||
|
||||
|
||||
# ==================== 依赖注入函数 ====================
|
||||
|
||||
def get_app_service(
|
||||
db: Annotated[Session, Depends(get_db)]
|
||||
) -> AppService:
|
||||
"""获取工作流服务(依赖注入)"""
|
||||
return AppService(db)
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
"""会话服务"""
|
||||
import uuid
|
||||
from typing import Optional, List, Tuple, Annotated
|
||||
from typing import Annotated
|
||||
from typing import Optional, List, Tuple
|
||||
|
||||
from fastapi import Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from sqlalchemy import select, desc
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.error_codes import BizCode
|
||||
from app.core.exceptions import BusinessException
|
||||
from app.core.exceptions import ResourceNotFoundException
|
||||
from app.core.logging_config import get_business_logger
|
||||
from app.db import get_db
|
||||
from app.models import Conversation, Message
|
||||
from app.core.exceptions import ResourceNotFoundException, BusinessException
|
||||
from app.core.error_codes import BizCode
|
||||
from app.core.logging_config import get_business_logger
|
||||
|
||||
logger = get_business_logger()
|
||||
|
||||
|
||||
@@ -11,31 +11,26 @@ from app.core.exceptions import BusinessException, PermissionDeniedException
|
||||
from app.core.logging_config import get_business_logger
|
||||
from app.models.user_model import User
|
||||
|
||||
# 获取业务逻辑专用日志器
|
||||
business_logger = get_business_logger()
|
||||
from app.models.workspace_model import (
|
||||
InviteStatus,
|
||||
Workspace,
|
||||
WorkspaceMember,
|
||||
WorkspaceRole,
|
||||
from app.schemas.workspace_schema import (
|
||||
WorkspaceModelsUpdate,
|
||||
)
|
||||
from sqlalchemy.orm import Session
|
||||
from app.models.workspace_model import Workspace, WorkspaceRole, InviteStatus, WorkspaceMember
|
||||
from app.repositories import workspace_repository
|
||||
from app.repositories.workspace_invite_repository import WorkspaceInviteRepository
|
||||
from app.schemas.workspace_schema import (
|
||||
InviteAcceptRequest,
|
||||
InviteValidateResponse,
|
||||
WorkspaceCreate,
|
||||
WorkspaceUpdate,
|
||||
WorkspaceInviteCreate,
|
||||
WorkspaceInviteResponse,
|
||||
WorkspaceMemberUpdate,
|
||||
WorkspaceModelsUpdate,
|
||||
WorkspaceUpdate,
|
||||
InviteValidateResponse,
|
||||
InviteAcceptRequest,
|
||||
WorkspaceMemberUpdate
|
||||
)
|
||||
from dotenv import load_dotenv
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
# 获取业务逻辑专用日志器
|
||||
business_logger = get_business_logger()
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
def switch_workspace(
|
||||
db: Session,
|
||||
@@ -329,7 +324,7 @@ def _check_workspace_admin_permission(db: Session, workspace_id: uuid.UUID, user
|
||||
)
|
||||
|
||||
# 使用统一权限服务检查管理权限
|
||||
from app.core.permissions import Action, Resource, Subject, permission_service
|
||||
from app.core.permissions import permission_service, Subject, Resource, Action
|
||||
|
||||
# 获取用户的工作空间成员关系
|
||||
member = workspace_repository.get_member_in_workspace(
|
||||
|
||||
Reference in New Issue
Block a user