feat: workflow和chat分离

1,增加了创建workflow的页面
2.删除了event
This commit is contained in:
2026-05-14 15:51:28 +00:00
parent c0e4fd34ae
commit 78bd6adc48
30 changed files with 1196 additions and 760 deletions
@@ -44,6 +44,7 @@ def database_exception(func):
raise e
except UserNotExistError as e:
logger.error(f"更改密码失败,用户不存在:{e}")
raise e
except Exception as e:
logger.exception(f"未预期的数据库错误: {e}")
raise e
@@ -12,9 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from kilostar.core.postgres_database.model.user import User
from kilostar.core.postgres_database.model.provider import Provider
from kilostar.core.postgres_database.model.individual import WorkerIndividual
from kilostar.core.postgres_database.model.user import User, UserAuthority
from kilostar.core.postgres_database.model.provider import ProviderModel
from kilostar.core.postgres_database.model.individual import (
BaseIndividualModel,
SpecialistIndividualModel,
OrdinaryIndividualModel,
SpecialIndividualModel,
)
from kilostar.core.postgres_database.model.workflow import (
Workflow,
WorkflowContextModel,
@@ -23,13 +28,30 @@ from kilostar.core.postgres_database.model.chat_history import (
ChatHistoryRegister,
ChatHistoryMessage,
)
from kilostar.core.postgres_database.model.system_node import SystemNodeConfigModel
# 兼容旧代码的别名
Provider = ProviderModel
SystemNodeConfig = SystemNodeConfigModel
# AgentType: 与 BaseIndividualModel 的 polymorphic_on 保持一致
from typing import Literal
AgentType = Literal["base", "specialist", "ordinary", "special"]
__all__ = [
"User",
"UserAuthority",
"ProviderModel",
"Provider",
"WorkerIndividual",
"BaseIndividualModel",
"SpecialistIndividualModel",
"OrdinaryIndividualModel",
"SpecialIndividualModel",
"Workflow",
"WorkflowContextModel",
"ChatHistoryRegister",
"ChatHistoryMessage",
"SystemNodeConfigModel",
"SystemNodeConfig",
"AgentType",
]
@@ -26,13 +26,13 @@ class ChatHistoryRegister(BaseDataModel):
__tablename__ = "chat_history_register"
chat_id: Mapped[str] = mapped_column(
String(64), primary_key=True, description="聊天会话ID"
String(64), primary_key=True, comment="聊天会话ID"
)
user_id: Mapped[str] = mapped_column(
String(64), index=True, description="归属的用户ID"
String(64), index=True, comment="归属的用户ID"
)
title: Mapped[str] = mapped_column(
String(255), default="新对话", description="对话标题"
String(255), default="新对话", comment="对话标题"
)
created_at: Mapped[str] = mapped_column(
DateTime(timezone=True), server_default=func.now()
@@ -50,15 +50,15 @@ class ChatHistoryMessage(BaseDataModel):
__tablename__ = "chat_history_message"
message_id: Mapped[str] = mapped_column(
String(64), primary_key=True, description="消息ID"
String(64), primary_key=True, comment="消息ID"
)
chat_id: Mapped[str] = mapped_column(
String(64), index=True, description="所属会话ID"
String(64), index=True, comment="所属会话ID"
)
message: Mapped[str] = mapped_column(String, description="消息体内容")
message: Mapped[str] = mapped_column(String, comment="消息体内容")
message_owner: Mapped[str] = mapped_column(
String(50),
description="消息发送方,例如 'user', 'regulatory_node', 'consciousness_node'",
comment="消息发送方,例如 'user', 'regulatory_node', 'consciousness_node'",
)
created_at: Mapped[str] = mapped_column(
DateTime(timezone=True), server_default=func.now()
@@ -14,7 +14,7 @@
from enum import Enum
from typing import List, Optional, Dict, Any
from sqlalchemy import String, Text, text, ForeignKey
from sqlalchemy import String, Text, text, ForeignKey, Enum as SAEnum
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.orm import Mapped, mapped_column, relationship
@@ -119,7 +119,8 @@ class SpecialIndividualModel(BaseIndividualModel):
ForeignKey("base_individual.agent_id", ondelete="CASCADE"), primary_key=True
)
modality_type: Mapped[ModalityType] = mapped_column(
default=ModalityType.MULTIMODAL, server_default=text("'multimodal'")
SAEnum(ModalityType),
default=ModalityType.MULTIMODAL,
)
multimodal_config: Mapped[Optional[Dict[str, Any]]] = mapped_column(JSONB)
@@ -22,22 +22,22 @@ class Workflow(BaseDataModel):
__tablename__ = "workflow"
trace_id: Mapped[str] = mapped_column(
String(64), primary_key=True, description="工作流唯一ID (Trace ID)"
String(64), primary_key=True, comment="工作流唯一ID (Trace ID)"
)
user_id: Mapped[str] = mapped_column(
String(64), index=True, description="创建该工作流的用户ID"
String(64), index=True, comment="创建该工作流的用户ID"
)
title: Mapped[str] = mapped_column(String(255), description="工作流标题/简短描述")
title: Mapped[str] = mapped_column(String(255), comment="工作流标题/简短描述")
command: Mapped[str] = mapped_column(
String, description="创建工作流的原始用户命令文本"
String, comment="创建工作流的原始用户命令文本"
)
status: Mapped[str] = mapped_column(
String(50),
default="creating",
description="工作流的总体状态 (例如: creating, running, pending, completed, failed等)",
comment="工作流的总体状态 (例如: creating, running, pending, completed, failed等)",
)
version: Mapped[str] = mapped_column(
String(50), default="v1.0", description="系统协议版本号"
String(50), default="v1.0", comment="系统协议版本号"
)
created_at: Mapped[str] = mapped_column(
DateTime(timezone=True), server_default=func.now()
@@ -51,27 +51,27 @@ class WorkflowContextModel(BaseDataModel):
__tablename__ = "workflow_context"
trace_id: Mapped[str] = mapped_column(
String(64), primary_key=True, description="对应的工作流 Trace ID"
String(64), primary_key=True, comment="对应的工作流 Trace ID"
)
workflow_status: Mapped[dict] = mapped_column(
JSONB, default=dict, description="工作流状态变更历史"
JSONB, default=dict, comment="工作流状态变更历史"
)
blackboard: Mapped[dict] = mapped_column(
JSONB, default=dict, description="大模型输出的存储区 (共享黑板)"
JSONB, default=dict, comment="大模型输出的存储区 (共享黑板)"
)
work_step_status: Mapped[dict] = mapped_column(
JSONB, nullable=True, description="工作流运行步骤状态"
JSONB, nullable=True, comment="工作流运行步骤状态"
)
workflow_pointer: Mapped[int] = mapped_column(
nullable=True, description="工作流指针,指向具体运行步骤位置"
nullable=True, comment="工作流指针,指向具体运行步骤位置"
)
workflow_log: Mapped[list] = mapped_column(
JSONB, default=list, description="工作流运行日志"
JSONB, default=list, comment="工作流运行日志"
)
work_link: Mapped[list] = mapped_column(
JSONB,
default=list,
description="工作链(即 WorkflowStep 的定义列表,包含图结构和原子动作)",
comment="工作链(即 WorkflowStep 的定义列表,包含图结构和原子动作)",
)
created_at: Mapped[str] = mapped_column(
DateTime(timezone=True), server_default=func.now()
@@ -20,12 +20,14 @@ from kilostar.core.postgres_database.model.chat_history import (
)
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession
from ulid import ULID
from kilostar.core.postgres_database.database_exception import database_exception
class ChatHistoryDatabase:
def __init__(self, async_session_maker: async_sessionmaker[AsyncSession]):
self.async_session_maker = async_session_maker
@database_exception
async def create_chat_session(
self, user_id: str, title: str = "新对话"
) -> ChatHistoryRegister:
@@ -37,6 +39,7 @@ class ChatHistoryDatabase:
await session.refresh(chat)
return chat
@database_exception
async def list_chat_sessions(self, user_id: str) -> List[ChatHistoryRegister]:
async with self.async_session_maker() as session:
statement = (
@@ -47,6 +50,7 @@ class ChatHistoryDatabase:
results = await session.execute(statement)
return results.scalars().all()
@database_exception
async def add_chat_message(
self, chat_id: str, message: str, message_owner: str
) -> ChatHistoryMessage:
@@ -71,6 +75,7 @@ class ChatHistoryDatabase:
await session.refresh(msg)
return msg
@database_exception
async def list_chat_messages(self, chat_id: str) -> List[ChatHistoryMessage]:
async with self.async_session_maker() as session:
statement = (
@@ -1,46 +0,0 @@
from sqlalchemy import select
from typing import List, Optional
from kilostar.core.postgres_database.model.workflow import EventRecord
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession
class EventDatabase:
def __init__(self, async_session_maker: async_sessionmaker[AsyncSession]):
self.async_session_maker = async_session_maker
async def upsert_event(self, trace_id: str, event_data_json: str) -> EventRecord:
async with self.async_session_maker() as session:
statement = select(EventRecord).where(EventRecord.trace_id == trace_id)
results = await session.execute(statement)
record = results.scalar_one_or_none()
if record:
record.event_data_json = event_data_json
else:
record = EventRecord(trace_id=trace_id, event_data_json=event_data_json)
session.add(record)
await session.commit()
await session.refresh(record)
return record
async def get_event(self, trace_id: str) -> Optional[EventRecord]:
async with self.async_session_maker() as session:
statement = select(EventRecord).where(EventRecord.trace_id == trace_id)
results = await session.execute(statement)
return results.scalar_one_or_none()
async def get_all_events(self) -> List[EventRecord]:
async with self.async_session_maker() as session:
statement = select(EventRecord)
results = await session.execute(statement)
return results.scalars().all()
async def delete_event(self, trace_id: str) -> bool:
async with self.async_session_maker() as session:
statement = select(EventRecord).where(EventRecord.trace_id == trace_id)
results = await session.execute(statement)
record = results.scalar_one_or_none()
if record:
await session.delete(record)
await session.commit()
return True
return False
@@ -12,13 +12,24 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from kilostar.core.postgres_database.model.individual import WorkerIndividual
from kilostar.core.postgres_database.model.individual import (
BaseIndividualModel,
SpecialistIndividualModel,
OrdinaryIndividualModel,
SpecialIndividualModel,
)
from sqlalchemy import select
from typing import List, Optional
from kilostar.core.postgres_database.database_exception import database_exception
from ulid import ULID
_AGENT_TYPE_MODEL_MAP = {
"specialist": SpecialistIndividualModel,
"ordinary": OrdinaryIndividualModel,
"special": SpecialIndividualModel,
}
class IndividualDatabase:
"""IndividualDatabase 核心组件类。
@@ -27,56 +38,50 @@ class IndividualDatabase:
def __init__(self, async_session_maker):
self.async_session_maker = async_session_maker
@staticmethod
def _select_model(agent_type: str):
return _AGENT_TYPE_MODEL_MAP.get(agent_type, BaseIndividualModel)
@database_exception
async def add_worker_individual(self, **kwargs) -> WorkerIndividual:
async def add_worker_individual(self, **kwargs):
"""创建并持久化新的 worker individual 实体。
接收构建参数,执行必要的数据校验与默认值填充后,将新记录安全地写入底层存储或系统注册表中。
Returns: (WorkerIndividual): 经由当前业务模型加工处理后所输出的具体数据实例或领域模型对象。"""
接收构建参数,执行必要的数据校验与默认值填充后,将新记录安全地写入底层存储或系统注册表中。"""
async with self.async_session_maker() as session:
agent_id = str(ULID())
individual = WorkerIndividual(agent_id=agent_id, **kwargs)
agent_type = kwargs.get("agent_type", "base")
model_cls = self._select_model(agent_type)
individual = model_cls(agent_id=agent_id, **kwargs)
session.add(individual)
await session.commit()
await session.refresh(individual)
return individual
@database_exception
async def get_worker_individual(self, agent_id: str) -> Optional[WorkerIndividual]:
"""检索并获取特定的 worker individual 数据集合或实例对象。
根据提供的查询条件或上下文凭证,从数据库、缓存或第三方服务中读取对应的资源状态。
Args: agent_id (str): 目标对象的唯一全局标识符 (UUID/ULID),用于在数据库表或缓存结构中精准匹配该 agent 实例。
Returns: (Optional[WorkerIndividual]): 经由当前业务模型加工处理后所输出的具体数据实例或领域模型对象。"""
async def get_worker_individual(self, agent_id: str):
"""检索并获取特定的 worker individual 数据集合或实例对象。"""
async with self.async_session_maker() as session:
statement = select(WorkerIndividual).where(
WorkerIndividual.agent_id == agent_id
statement = select(BaseIndividualModel).where(
BaseIndividualModel.agent_id == agent_id
)
results = await session.execute(statement)
return results.scalar_one_or_none()
@database_exception
async def get_worker_individual_list(self, owner_id: str) -> List[WorkerIndividual]:
"""检索并获取特定的 worker individual list 数据集合或实例对象。
根据提供的查询条件或上下文凭证,从数据库、缓存或第三方服务中读取对应的资源状态。
Args: owner_id (str): 目标对象的唯一全局标识符 (UUID/ULID),用于在数据库表或缓存结构中精准匹配该 owner 实例。
Returns: (List[WorkerIndividual]): 经过筛选、排序或分页处理后的实体对象列表集合。"""
async def get_worker_individual_list(self, owner_id: str):
"""检索并获取特定的 worker individual list 数据集合或实例对象。"""
async with self.async_session_maker() as session:
statement = select(WorkerIndividual).where(
WorkerIndividual.owner_id == owner_id
statement = select(BaseIndividualModel).where(
BaseIndividualModel.owner_id == owner_id
)
results = await session.execute(statement)
return list(results.scalars().all())
@database_exception
async def update_worker_individual(
self, agent_id: str, **kwargs
) -> Optional[WorkerIndividual]:
"""对现有的 worker individual 进行状态更新或属性覆盖。
基于增量变更原则,合并最新的配置或数据,并触发相关依赖组件的缓存刷新或事件通知。
Args: agent_id (str): 目标对象的唯一全局标识符 (UUID/ULID),用于在数据库表或缓存结构中精准匹配该 agent 实例。
Returns: (Optional[WorkerIndividual]): 经由当前业务模型加工处理后所输出的具体数据实例或领域模型对象。"""
async def update_worker_individual(self, agent_id: str, **kwargs):
"""对现有的 worker individual 进行状态更新或属性覆盖。"""
async with self.async_session_maker() as session:
statement = select(WorkerIndividual).where(
WorkerIndividual.agent_id == agent_id
statement = select(BaseIndividualModel).where(
BaseIndividualModel.agent_id == agent_id
)
results = await session.execute(statement)
individual = results.scalar_one_or_none()
@@ -92,13 +97,10 @@ class IndividualDatabase:
@database_exception
async def delete_worker_individual(self, agent_id: str) -> bool:
"""安全地移除或注销 worker individual。
执行物理删除或逻辑删除操作,并妥善清理相关的关联数据及占用资源。
Args: agent_id (str): 目标对象的唯一全局标识符 (UUID/ULID),用于在数据库表或缓存结构中精准匹配该 agent 实例。
Returns: (bool): 一个布尔型结果标志,明确返回 True 表示该操作成功应用或条件达成,False 则表示失败或被拒绝。"""
"""安全地移除或注销 worker individual。"""
async with self.async_session_maker() as session:
statement = select(WorkerIndividual).where(
WorkerIndividual.agent_id == agent_id
statement = select(BaseIndividualModel).where(
BaseIndividualModel.agent_id == agent_id
)
results = await session.execute(statement)
individual = results.scalar_one_or_none()
@@ -109,11 +111,9 @@ class IndividualDatabase:
return True
@database_exception
async def get_all_worker_individual(self) -> List[WorkerIndividual]:
"""检索并获取特定的 all worker individual 数据集合或实例对象。
根据提供的查询条件或上下文凭证,从数据库、缓存或第三方服务中读取对应的资源状态。
Returns: (List[WorkerIndividual]): 经过筛选、排序或分页处理后的实体对象列表集合。"""
async def get_all_worker_individual(self):
"""检索并获取特定的 all worker individual 数据集合或实例对象。"""
async with self.async_session_maker() as session:
statement = select(WorkerIndividual)
statement = select(BaseIndividualModel)
results = await session.execute(statement)
return list(results.scalars().all())
@@ -14,7 +14,7 @@
from typing import List
from kilostar.core.postgres_database.model.provider import Provider
from kilostar.core.postgres_database.model.provider import ProviderModel
from sqlalchemy import select
from kilostar.core.postgres_database.database_exception import database_exception
@@ -27,21 +27,25 @@ class ProviderDatabase:
self.async_session_maker = async_session_maker
@database_exception
async def get_provider(self) -> List[Provider]:
async def get_provider(self) -> List[ProviderModel]:
"""检索并获取特定的 provider 数据集合或实例对象。
根据提供的查询条件或上下文凭证,从数据库、缓存或第三方服务中读取对应的资源状态。
Returns: (List[Provider]): 经过筛选、排序或分页处理后的实体对象列表集合。"""
Returns: (List[ProviderModel]): 经过筛选、排序或分页处理后的实体对象列表集合。"""
async with self.async_session_maker() as session:
statement = select(Provider)
statement = select(ProviderModel)
results = await session.execute(statement)
results = results.scalars().all()
providers = [
Provider(
ProviderModel(
provider_id=provider.provider_id,
provider_title=provider.provider_title,
provider_url=provider.provider_url,
provider_apikey=provider.provider_apikey,
provider_models=provider.provider_models,
provider_type=provider.provider_type,
provider_owner=provider.provider_owner,
provider_status=provider.provider_status,
is_active=provider.is_active,
)
for provider in results
]
@@ -53,7 +57,7 @@ class ProviderDatabase:
接收构建参数,执行必要的数据校验与默认值填充后,将新记录安全地写入底层存储或系统注册表中。
Returns: (None): 经由当前业务模型加工处理后所输出的具体数据实例或领域模型对象。"""
async with self.async_session_maker() as session:
provider = Provider(**kwargs)
provider = ProviderModel(**kwargs)
session.add(provider)
await session.commit()
@@ -64,19 +68,19 @@ class ProviderDatabase:
Args: provider_id (str): 目标对象的唯一全局标识符 (UUID/ULID),用于在数据库表或缓存结构中精准匹配该 provider 实例。
Returns: (None): 经由当前业务模型加工处理后所输出的具体数据实例或领域模型对象。"""
async with self.async_session_maker() as session:
provider = await session.get(Provider, provider_id)
provider = await session.get(ProviderModel, provider_id)
if provider is not None:
session.delete(provider)
await session.commit()
@database_exception
async def update_provider(self, provider_id: str, **kwargs) -> Provider:
async def update_provider(self, provider_id: str, **kwargs) -> None:
"""对现有的 provider 进行状态更新或属性覆盖。
基于增量变更原则,合并最新的配置或数据,并触发相关依赖组件的缓存刷新或事件通知。
Args: provider_id (str): 目标对象的唯一全局标识符 (UUID/ULID),用于在数据库表或缓存结构中精准匹配该 provider 实例。
Returns: (Provider): 经由当前业务模型加工处理后所输出的具体数据实例或领域模型对象。"""
async with self.async_session_maker() as session:
provider = await session.get(Provider, provider_id)
provider = await session.get(ProviderModel, provider_id)
if provider is not None:
for key, value in kwargs.items():
setattr(provider, key, value)
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from kilostar.core.postgres_database.model.system_node import SystemNodeConfig
from kilostar.core.postgres_database.model.system_node import SystemNodeConfigModel
from sqlalchemy import select
from typing import List, Optional
from kilostar.core.postgres_database.database_exception import database_exception
@@ -32,14 +32,14 @@ class SystemNodeDatabase:
provider_title: str,
model_id: str,
tools: Optional[List[str]] = None,
) -> SystemNodeConfig:
) -> SystemNodeConfigModel:
"""执行与 upsert system node config 相关的核心业务流转操作。
该方法封装了具体的算法策略或状态控制逻辑,确保操作能够在事务上下文中被原子且一致地执行。
Args: node_name (str): 赋予该实体的人类可读名称或标题字符串,主要用于前端 UI 展示、日志记录或模糊检索。 provider_title (str): 目标对象的唯一全局标识符 (UUID/ULID),用于在数据库表或缓存结构中精准匹配该 provider_title 实例。 model_id (str): 目标对象的唯一全局标识符 (UUID/ULID),用于在数据库表或缓存结构中精准匹配该 model 实例。 tools (Optional[List[str]]): 控制逻辑流向的具体字符串参数,指定了期望的 tools 内容。
Returns: (SystemNodeConfig): 经由当前业务模型加工处理后所输出的具体数据实例或领域模型对象。"""
Returns: (SystemNodeConfigModel): 经由当前业务模型加工处理后所输出的具体数据实例或领域模型对象。"""
async with self.async_session_maker() as session:
statement = select(SystemNodeConfig).where(
SystemNodeConfig.node_name == node_name
statement = select(SystemNodeConfigModel).where(
SystemNodeConfigModel.node_name == node_name
)
results = await session.execute(statement)
config = results.scalar_one_or_none()
@@ -49,7 +49,7 @@ class SystemNodeDatabase:
if tools is not None:
config.tools = tools
else:
config = SystemNodeConfig(
config = SystemNodeConfigModel(
node_name=node_name,
provider_title=provider_title,
model_id=model_id,
@@ -61,26 +61,26 @@ class SystemNodeDatabase:
return config
@database_exception
async def get_all_system_node_configs(self) -> List[SystemNodeConfig]:
async def get_all_system_node_configs(self) -> List[SystemNodeConfigModel]:
"""检索并获取特定的 all system node configs 数据集合或实例对象。
根据提供的查询条件或上下文凭证,从数据库、缓存或第三方服务中读取对应的资源状态。
Returns: (List[SystemNodeConfig]): 经过筛选、排序或分页处理后的实体对象列表集合。"""
Returns: (List[SystemNodeConfigModel]): 经过筛选、排序或分页处理后的实体对象列表集合。"""
async with self.async_session_maker() as session:
statement = select(SystemNodeConfig)
statement = select(SystemNodeConfigModel)
results = await session.execute(statement)
return list(results.scalars().all())
@database_exception
async def get_system_node_config(
self, node_name: str
) -> Optional[SystemNodeConfig]:
) -> Optional[SystemNodeConfigModel]:
"""检索并获取特定的 system node config 数据集合或实例对象。
根据提供的查询条件或上下文凭证,从数据库、缓存或第三方服务中读取对应的资源状态。
Args: node_name (str): 赋予该实体的人类可读名称或标题字符串,主要用于前端 UI 展示、日志记录或模糊检索。
Returns: (Optional[SystemNodeConfig]): 经由当前业务模型加工处理后所输出的具体数据实例或领域模型对象。"""
Returns: (Optional[SystemNodeConfigModel]): 经由当前业务模型加工处理后所输出的具体数据实例或领域模型对象。"""
async with self.async_session_maker() as session:
statement = select(SystemNodeConfig).where(
SystemNodeConfig.node_name == node_name
statement = select(SystemNodeConfigModel).where(
SystemNodeConfigModel.node_name == node_name
)
results = await session.execute(statement)
return results.scalar_one_or_none()
@@ -70,7 +70,7 @@ class AuthDatabase:
raise UserNotExistError()
if not Accessor.verify_password(old_password, user.hashed_password):
raise UserPasswordError()
user.hashed_password = new_password
user.hashed_password = Accessor.hash_password(new_password)
session.add(user)
await session.commit()
await session.refresh(user)
@@ -19,12 +19,14 @@ from kilostar.core.postgres_database.model.workflow import (
WorkflowContextModel,
)
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession
from kilostar.core.postgres_database.database_exception import database_exception
class WorkflowDatabase:
def __init__(self, async_session_maker: async_sessionmaker[AsyncSession]):
self.async_session_maker = async_session_maker
@database_exception
async def create_workflow(
self, trace_id: str, user_id: str, title: str, command: str
) -> Workflow:
@@ -41,12 +43,14 @@ class WorkflowDatabase:
await session.refresh(wf)
return wf
@database_exception
async def get_workflow(self, trace_id: str) -> Optional[Workflow]:
async with self.async_session_maker() as session:
statement = select(Workflow).where(Workflow.trace_id == trace_id)
results = await session.execute(statement)
return results.scalar_one_or_none()
@database_exception
async def update_workflow_status(
self, trace_id: str, status: str
) -> Optional[Workflow]:
@@ -60,12 +64,14 @@ class WorkflowDatabase:
await session.refresh(record)
return record
@database_exception
async def list_workflows(self, user_id: str) -> List[Workflow]:
async with self.async_session_maker() as session:
statement = select(Workflow).where(Workflow.user_id == user_id)
results = await session.execute(statement)
return results.scalars().all()
@database_exception
async def upsert_workflow_context(
self, trace_id: str, **kwargs
) -> WorkflowContextModel:
@@ -85,6 +91,7 @@ class WorkflowDatabase:
await session.refresh(record)
return record
@database_exception
async def get_workflow_context(
self, trace_id: str
) -> Optional[WorkflowContextModel]:
+22 -25
View File
@@ -20,8 +20,26 @@ from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
from kilostar.core.postgres_database.model.base import BaseDataModel
# 在 create_all 前显式导入所有 ORM 模型类,确保它们注册到 metadata
from kilostar.core.postgres_database.model.provider import ProviderModel
from kilostar.core.postgres_database.model.user import User
from kilostar.core.postgres_database.model.individual import (
BaseIndividualModel,
SpecialistIndividualModel,
OrdinaryIndividualModel,
SpecialIndividualModel,
)
from kilostar.core.postgres_database.model.workflow import (
Workflow,
WorkflowContextModel,
)
from kilostar.core.postgres_database.model.chat_history import (
ChatHistoryRegister,
ChatHistoryMessage,
)
from kilostar.core.postgres_database.model.system_node import SystemNodeConfigModel
from .module.individual import IndividualDatabase
from .module.event import EventDatabase
from .module.user import AuthDatabase
from .module.provider import ProviderDatabase
from .module.system_node import SystemNodeDatabase
@@ -51,7 +69,6 @@ class PostgresDatabase:
self._auth_database = AuthDatabase(self.async_session_maker)
self._provider_database = ProviderDatabase(self.async_session_maker)
self._individual_database = IndividualDatabase(self.async_session_maker)
self._event_database = EventDatabase(self.async_session_maker)
self._system_node_database = SystemNodeDatabase(self.async_session_maker)
self._workflow_database = WorkflowDatabase(self.async_session_maker)
self._chat_history_database = ChatHistoryDatabase(self.async_session_maker)
@@ -59,16 +76,13 @@ class PostgresDatabase:
self.ready_event = asyncio.Event()
async def init_db(self) -> None:
"""完成 db 模块的启动与依赖初始化。
在系统引导或服务拉起阶段被调用,负责建立网络连接、分配基础内存资源及注册核心服务组件。
Returns: (None): 经由当前业务模型加工处理后所输出的具体数据实例或领域模型对象。"""
try:
async with self.async_engine.begin() as conn:
await conn.run_sync(BaseDataModel.metadata.create_all)
print("✅ 数据库表创建/验证完成")
except Exception as e:
# Provide a warning if the database is not accessible, allowing
# the app to start up for development/UI tests without crashing immediately.
print(f"Warning: Failed to initialize PostgreSQL database: {e}")
print(f"❌ 数据库初始化失败: {e}")
raise
finally:
self.ready_event.set()
@@ -242,23 +256,6 @@ class PostgresDatabase:
await self.ready_event.wait()
return await self._individual_database.get_all_worker_individual()
# Event Database Methods
async def upsert_event(self, trace_id: str, event_data_json: str):
await self.ready_event.wait()
return await self._event_database.upsert_event(trace_id, event_data_json)
async def get_event(self, trace_id: str):
await self.ready_event.wait()
return await self._event_database.get_event(trace_id)
async def get_all_events(self):
await self.ready_event.wait()
return await self._event_database.get_all_events()
async def delete_event(self, trace_id: str):
await self.ready_event.wait()
return await self._event_database.delete_event(trace_id)
# Workflow Database Methods
async def create_workflow(
self, trace_id: str, user_id: str, title: str, command: str