Initial lightweight AI agent admin

This commit is contained in:
Hermes Agent
2026-06-08 15:05:57 +08:00
commit 0e485492cf
49 changed files with 4520 additions and 0 deletions
+31
View File
@@ -0,0 +1,31 @@
from app.models.ai import (
Agent,
AgentConversation,
AgentMessage,
AgentTeam,
CollaborationRun,
KnowledgeBase,
LLMModel,
LLMProvider,
Workflow,
WorkflowRun,
)
from app.models.core import Announcement, Menu, Permission, Role, User
__all__ = [
"Agent",
"AgentConversation",
"AgentMessage",
"AgentTeam",
"Announcement",
"CollaborationRun",
"KnowledgeBase",
"LLMModel",
"LLMProvider",
"Menu",
"Permission",
"Role",
"User",
"Workflow",
"WorkflowRun",
]
+141
View File
@@ -0,0 +1,141 @@
from sqlalchemy import Boolean, DateTime, Float, ForeignKey, Integer, JSON, String, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.core.database import Base
from app.models.base import TimestampMixin
class LLMProvider(TimestampMixin, Base):
__tablename__ = "ai_llm_provider"
name: Mapped[str] = mapped_column(String(100))
code: Mapped[str] = mapped_column(String(80), unique=True, index=True)
provider_type: Mapped[str] = mapped_column(String(40), default="openai_compatible")
base_url: Mapped[str] = mapped_column(String(300), default="")
api_key: Mapped[str] = mapped_column(String(500), default="")
status: Mapped[str] = mapped_column(String(20), default="enabled")
models: Mapped[list["LLMModel"]] = relationship("LLMModel", back_populates="provider")
class LLMModel(TimestampMixin, Base):
__tablename__ = "ai_llm_model"
provider_id: Mapped[str] = mapped_column(String(32), ForeignKey("ai_llm_provider.id"), index=True)
name: Mapped[str] = mapped_column(String(120))
display_name: Mapped[str] = mapped_column(String(120), default="")
context_length: Mapped[int] = mapped_column(Integer, default=8192)
supports_streaming: Mapped[bool] = mapped_column(Boolean, default=True)
supports_function_call: Mapped[bool] = mapped_column(Boolean, default=False)
default_temperature: Mapped[float] = mapped_column(Float, default=0.7)
default_max_tokens: Mapped[int] = mapped_column(Integer, default=2048)
status: Mapped[str] = mapped_column(String(20), default="enabled")
provider: Mapped[LLMProvider] = relationship("LLMProvider", back_populates="models")
class Agent(TimestampMixin, Base):
__tablename__ = "ai_agent"
name: Mapped[str] = mapped_column(String(100))
code: Mapped[str] = mapped_column(String(80), unique=True, index=True)
description: Mapped[str] = mapped_column(Text, default="")
avatar: Mapped[str] = mapped_column(String(300), default="")
status: Mapped[str] = mapped_column(String(20), default="draft")
persona: Mapped[dict] = mapped_column(JSON, default=dict)
system_prompt: Mapped[str] = mapped_column(Text, default="")
model_id: Mapped[str | None] = mapped_column(String(32), ForeignKey("ai_llm_model.id"), nullable=True)
temperature: Mapped[float] = mapped_column(Float, default=0.7)
max_tokens: Mapped[int] = mapped_column(Integer, default=2048)
tools: Mapped[list] = mapped_column(JSON, default=list)
knowledge_base_ids: Mapped[list] = mapped_column(JSON, default=list)
enable_memory: Mapped[bool] = mapped_column(Boolean, default=True)
memory_window: Mapped[int] = mapped_column(Integer, default=10)
model: Mapped[LLMModel | None] = relationship("LLMModel")
class AgentConversation(TimestampMixin, Base):
__tablename__ = "ai_agent_conversation"
agent_id: Mapped[str] = mapped_column(String(32), ForeignKey("ai_agent.id"), index=True)
user_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
title: Mapped[str] = mapped_column(String(160), default="新建对话")
total_tokens: Mapped[int] = mapped_column(Integer, default=0)
agent: Mapped[Agent] = relationship("Agent")
messages: Mapped[list["AgentMessage"]] = relationship("AgentMessage", back_populates="conversation")
class AgentMessage(TimestampMixin, Base):
__tablename__ = "ai_agent_message"
conversation_id: Mapped[str] = mapped_column(String(32), ForeignKey("ai_agent_conversation.id"), index=True)
role: Mapped[str] = mapped_column(String(20))
content: Mapped[str] = mapped_column(Text, default="")
status: Mapped[str] = mapped_column(String(20), default="completed")
reasoning_steps: Mapped[list] = mapped_column(JSON, default=list)
total_tokens: Mapped[int] = mapped_column(Integer, default=0)
elapsed_time: Mapped[int] = mapped_column(Integer, default=0)
conversation: Mapped[AgentConversation] = relationship("AgentConversation", back_populates="messages")
class Workflow(TimestampMixin, Base):
__tablename__ = "ai_workflow"
name: Mapped[str] = mapped_column(String(100))
code: Mapped[str] = mapped_column(String(80), unique=True, index=True)
description: Mapped[str] = mapped_column(Text, default="")
status: Mapped[str] = mapped_column(String(20), default="draft")
version: Mapped[int] = mapped_column(Integer, default=1)
published_version: Mapped[int | None] = mapped_column(Integer, nullable=True)
definition: Mapped[dict] = mapped_column(JSON, default=dict)
published_definition: Mapped[dict] = mapped_column(JSON, default=dict)
input_variables: Mapped[list] = mapped_column(JSON, default=list)
output_variables: Mapped[list] = mapped_column(JSON, default=list)
run_count: Mapped[int] = mapped_column(Integer, default=0)
class WorkflowRun(TimestampMixin, Base):
__tablename__ = "ai_workflow_run"
workflow_id: Mapped[str] = mapped_column(String(32), ForeignKey("ai_workflow.id"), index=True)
status: Mapped[str] = mapped_column(String(20), default="running")
trigger_type: Mapped[str] = mapped_column(String(40), default="api")
inputs: Mapped[dict] = mapped_column(JSON, default=dict)
outputs: Mapped[dict] = mapped_column(JSON, default=dict)
execution_log: Mapped[list] = mapped_column(JSON, default=list)
error_message: Mapped[str] = mapped_column(Text, default="")
total_tokens: Mapped[int] = mapped_column(Integer, default=0)
elapsed_time: Mapped[int] = mapped_column(Integer, default=0)
started_at: Mapped[object | None] = mapped_column(DateTime, nullable=True)
completed_at: Mapped[object | None] = mapped_column(DateTime, nullable=True)
workflow: Mapped[Workflow] = relationship("Workflow")
class KnowledgeBase(TimestampMixin, Base):
__tablename__ = "ai_knowledge_base"
name: Mapped[str] = mapped_column(String(120))
code: Mapped[str] = mapped_column(String(80), unique=True, index=True)
description: Mapped[str] = mapped_column(Text, default="")
status: Mapped[str] = mapped_column(String(20), default="enabled")
class AgentTeam(TimestampMixin, Base):
__tablename__ = "ai_agent_team"
name: Mapped[str] = mapped_column(String(120))
code: Mapped[str] = mapped_column(String(80), unique=True, index=True)
description: Mapped[str] = mapped_column(Text, default="")
mode: Mapped[str] = mapped_column(String(20), default="sequential")
members: Mapped[list] = mapped_column(JSON, default=list)
status: Mapped[str] = mapped_column(String(20), default="enabled")
class CollaborationRun(TimestampMixin, Base):
__tablename__ = "ai_collaboration_run"
team_id: Mapped[str] = mapped_column(String(32), ForeignKey("ai_agent_team.id"), index=True)
task: Mapped[str] = mapped_column(Text, default="")
status: Mapped[str] = mapped_column(String(20), default="running")
messages: Mapped[list] = mapped_column(JSON, default=list)
final_answer: Mapped[str] = mapped_column(Text, default="")
elapsed_time: Mapped[int] = mapped_column(Integer, default=0)
team: Mapped[AgentTeam] = relationship("AgentTeam")
+19
View File
@@ -0,0 +1,19 @@
from datetime import datetime
from uuid import uuid4
from sqlalchemy import Boolean, DateTime, Integer, String
from sqlalchemy.orm import Mapped, mapped_column
from app.core.database import Base
def new_id() -> str:
return uuid4().hex
class TimestampMixin:
id: Mapped[str] = mapped_column(String(32), primary_key=True, default=new_id)
sort: Mapped[int] = mapped_column(Integer, default=0)
is_deleted: Mapped[bool] = mapped_column(Boolean, default=False, index=True)
created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow)
updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
+71
View File
@@ -0,0 +1,71 @@
from sqlalchemy import Boolean, Column, ForeignKey, String, Table, Text
from sqlalchemy.orm import Mapped, mapped_column, relationship
from app.core.database import Base
from app.models.base import TimestampMixin
role_permission = Table(
"core_role_permission",
Base.metadata,
Column("role_id", String(32), ForeignKey("core_role.id"), primary_key=True),
Column("permission_id", String(32), ForeignKey("core_permission.id"), primary_key=True),
)
user_role = Table(
"core_user_role",
Base.metadata,
Column("user_id", String(32), ForeignKey("core_user.id"), primary_key=True),
Column("role_id", String(32), ForeignKey("core_role.id"), primary_key=True),
)
class User(TimestampMixin, Base):
__tablename__ = "core_user"
email: Mapped[str] = mapped_column(String(120), unique=True, index=True)
username: Mapped[str] = mapped_column(String(80), unique=True, index=True)
password_hash: Mapped[str] = mapped_column(String(200))
nickname: Mapped[str] = mapped_column(String(80), default="")
status: Mapped[str] = mapped_column(String(20), default="enabled")
is_superuser: Mapped[bool] = mapped_column(Boolean, default=False)
roles: Mapped[list["Role"]] = relationship("Role", secondary=user_role, back_populates="users")
class Role(TimestampMixin, Base):
__tablename__ = "core_role"
name: Mapped[str] = mapped_column(String(80), unique=True)
code: Mapped[str] = mapped_column(String(80), unique=True, index=True)
description: Mapped[str] = mapped_column(Text, default="")
status: Mapped[str] = mapped_column(String(20), default="enabled")
users: Mapped[list[User]] = relationship("User", secondary=user_role, back_populates="roles")
permissions: Mapped[list["Permission"]] = relationship("Permission", secondary=role_permission)
class Permission(TimestampMixin, Base):
__tablename__ = "core_permission"
name: Mapped[str] = mapped_column(String(100))
code: Mapped[str] = mapped_column(String(120), unique=True, index=True)
resource: Mapped[str] = mapped_column(String(80), default="")
action: Mapped[str] = mapped_column(String(40), default="")
class Menu(TimestampMixin, Base):
__tablename__ = "core_menu"
parent_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True)
title: Mapped[str] = mapped_column(String(100))
path: Mapped[str] = mapped_column(String(200), default="")
icon: Mapped[str] = mapped_column(String(100), default="")
permission_code: Mapped[str] = mapped_column(String(120), default="")
visible: Mapped[bool] = mapped_column(Boolean, default=True)
class Announcement(TimestampMixin, Base):
__tablename__ = "core_announcement"
title: Mapped[str] = mapped_column(String(160))
content: Mapped[str] = mapped_column(Text, default="")
status: Mapped[str] = mapped_column(String(20), default="draft")