feat(database): add schema bootstrap and config
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -104,6 +104,15 @@ class Settings(BaseSettings):
|
|||||||
WEB_SEARCH_DEFAULT_LIMIT: int = 5
|
WEB_SEARCH_DEFAULT_LIMIT: int = 5
|
||||||
WEB_SEARCH_TIMEOUT_SECONDS: int = 10
|
WEB_SEARCH_TIMEOUT_SECONDS: int = 10
|
||||||
|
|
||||||
|
# === Hermes 风格升级开关 ===
|
||||||
|
ENABLE_RETROSPECTIVE: bool = True
|
||||||
|
ENABLE_SESSION_RETROSPECTIVE_SEARCH: bool = True
|
||||||
|
ENABLE_RUNTIME_SKILL_SHORTLIST: bool = True
|
||||||
|
ENABLE_LEARNING_SIGNALS: bool = True
|
||||||
|
ENABLE_SKILL_PROMOTION: bool = True
|
||||||
|
ENABLE_LEARNED_SKILL_LOADING: bool = True
|
||||||
|
ENABLE_PARALLEL_TASK_GRAPH: bool = True
|
||||||
|
|
||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
settings.DATABASE_URL = settings.DATABASE_URL.replace("./data", _resolve_path("./data"), 1)
|
settings.DATABASE_URL = settings.DATABASE_URL.replace("./data", _resolve_path("./data"), 1)
|
||||||
|
|||||||
@@ -39,10 +39,12 @@ async def init_db():
|
|||||||
await ensure_message_columns(conn)
|
await ensure_message_columns(conn)
|
||||||
await ensure_conversation_columns(conn)
|
await ensure_conversation_columns(conn)
|
||||||
await ensure_document_columns(conn)
|
await ensure_document_columns(conn)
|
||||||
|
await ensure_memory_columns(conn)
|
||||||
await ensure_user_columns(conn)
|
await ensure_user_columns(conn)
|
||||||
await ensure_forum_columns(conn)
|
await ensure_forum_columns(conn)
|
||||||
await ensure_agent_columns(conn)
|
await ensure_agent_columns(conn)
|
||||||
await ensure_skill_columns(conn)
|
await ensure_skill_columns(conn)
|
||||||
|
await ensure_learning_artifact_tables(conn)
|
||||||
|
|
||||||
|
|
||||||
async def ensure_log_columns(conn):
|
async def ensure_log_columns(conn):
|
||||||
@@ -115,6 +117,28 @@ async def ensure_document_columns(conn):
|
|||||||
await conn.execute(text(ddl))
|
await conn.execute(text(ddl))
|
||||||
|
|
||||||
|
|
||||||
|
async def ensure_memory_columns(conn):
|
||||||
|
rows = await _get_table_info(conn, 'user_memories')
|
||||||
|
if not rows:
|
||||||
|
return
|
||||||
|
|
||||||
|
columns = {row[1] for row in rows}
|
||||||
|
required_columns = {
|
||||||
|
'frequency_count': "ALTER TABLE user_memories ADD COLUMN frequency_count INTEGER DEFAULT 0",
|
||||||
|
'emotion_tags': "ALTER TABLE user_memories ADD COLUMN emotion_tags JSON",
|
||||||
|
'importance_score': "ALTER TABLE user_memories ADD COLUMN importance_score FLOAT DEFAULT 0.5",
|
||||||
|
'importance_level': "ALTER TABLE user_memories ADD COLUMN importance_level VARCHAR(20) DEFAULT 'medium'",
|
||||||
|
'associated_topics': "ALTER TABLE user_memories ADD COLUMN associated_topics JSON",
|
||||||
|
'decay_score': "ALTER TABLE user_memories ADD COLUMN decay_score FLOAT DEFAULT 1.0",
|
||||||
|
'is_archived': "ALTER TABLE user_memories ADD COLUMN is_archived BOOLEAN DEFAULT 0",
|
||||||
|
'last_accessed_at': "ALTER TABLE user_memories ADD COLUMN last_accessed_at DATETIME",
|
||||||
|
'archive_at': "ALTER TABLE user_memories ADD COLUMN archive_at DATETIME",
|
||||||
|
}
|
||||||
|
for column, ddl in required_columns.items():
|
||||||
|
if column not in columns:
|
||||||
|
await conn.execute(text(ddl))
|
||||||
|
|
||||||
|
|
||||||
async def ensure_user_columns(conn):
|
async def ensure_user_columns(conn):
|
||||||
rows = await _get_table_info(conn, 'users')
|
rows = await _get_table_info(conn, 'users')
|
||||||
if not rows:
|
if not rows:
|
||||||
@@ -181,6 +205,14 @@ async def ensure_skill_columns(conn):
|
|||||||
'output_format': "ALTER TABLE skills ADD COLUMN output_format TEXT",
|
'output_format': "ALTER TABLE skills ADD COLUMN output_format TEXT",
|
||||||
'is_builtin': "ALTER TABLE skills ADD COLUMN is_builtin BOOLEAN DEFAULT 0 NOT NULL",
|
'is_builtin': "ALTER TABLE skills ADD COLUMN is_builtin BOOLEAN DEFAULT 0 NOT NULL",
|
||||||
'team_id': "ALTER TABLE skills ADD COLUMN team_id VARCHAR(36)",
|
'team_id': "ALTER TABLE skills ADD COLUMN team_id VARCHAR(36)",
|
||||||
|
'status': "ALTER TABLE skills ADD COLUMN status VARCHAR(20) DEFAULT 'active' NOT NULL",
|
||||||
|
'scope': "ALTER TABLE skills ADD COLUMN scope JSON DEFAULT '[]' NOT NULL",
|
||||||
|
'effectiveness': "ALTER TABLE skills ADD COLUMN effectiveness FLOAT DEFAULT 0.0 NOT NULL",
|
||||||
|
'review_after': "ALTER TABLE skills ADD COLUMN review_after DATETIME",
|
||||||
|
'candidate_count': "ALTER TABLE skills ADD COLUMN candidate_count INTEGER DEFAULT 0 NOT NULL",
|
||||||
|
'candidate_source_hashes': "ALTER TABLE skills ADD COLUMN candidate_source_hashes JSON DEFAULT '[]' NOT NULL",
|
||||||
|
'activation_count': "ALTER TABLE skills ADD COLUMN activation_count INTEGER DEFAULT 0 NOT NULL",
|
||||||
|
'last_activated_at': "ALTER TABLE skills ADD COLUMN last_activated_at DATETIME",
|
||||||
}
|
}
|
||||||
for column, ddl in required_columns.items():
|
for column, ddl in required_columns.items():
|
||||||
if column not in columns:
|
if column not in columns:
|
||||||
@@ -205,6 +237,48 @@ async def ensure_skill_columns(conn):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def ensure_learning_artifact_tables(conn):
|
||||||
|
await conn.execute(
|
||||||
|
text(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS learning_artifacts (
|
||||||
|
id VARCHAR(36) PRIMARY KEY,
|
||||||
|
created_at DATETIME NOT NULL,
|
||||||
|
updated_at DATETIME NOT NULL,
|
||||||
|
user_id VARCHAR(36) NOT NULL,
|
||||||
|
conversation_id VARCHAR(36) NOT NULL,
|
||||||
|
retrospective_id VARCHAR(36),
|
||||||
|
artifact_type VARCHAR(32) NOT NULL,
|
||||||
|
artifact_key VARCHAR(128),
|
||||||
|
summary_text TEXT NOT NULL,
|
||||||
|
payload JSON NOT NULL,
|
||||||
|
recorded_at DATETIME NOT NULL
|
||||||
|
)
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await conn.execute(
|
||||||
|
text(
|
||||||
|
"CREATE INDEX IF NOT EXISTS ix_learning_artifacts_user_id ON learning_artifacts (user_id)"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await conn.execute(
|
||||||
|
text(
|
||||||
|
"CREATE INDEX IF NOT EXISTS ix_learning_artifacts_conversation_id ON learning_artifacts (conversation_id)"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await conn.execute(
|
||||||
|
text(
|
||||||
|
"CREATE INDEX IF NOT EXISTS ix_learning_artifacts_retrospective_id ON learning_artifacts (retrospective_id)"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await conn.execute(
|
||||||
|
text(
|
||||||
|
"CREATE INDEX IF NOT EXISTS ix_learning_artifacts_artifact_type ON learning_artifacts (artifact_type)"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def _backfill_usernames(conn):
|
async def _backfill_usernames(conn):
|
||||||
result = await conn.execute(text("SELECT id, email, username FROM users ORDER BY created_at, id"))
|
result = await conn.execute(text("SELECT id, email, username FROM users ORDER BY created_at, id"))
|
||||||
users = result.fetchall()
|
users = result.fetchall()
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ from app.models.forum import ForumPost, ForumReply
|
|||||||
from app.models.agent import Agent, AgentMessage
|
from app.models.agent import Agent, AgentMessage
|
||||||
from app.models.conversation import Conversation, Message
|
from app.models.conversation import Conversation, Message
|
||||||
from app.models.knowledge_graph import KGNode, KGEdge
|
from app.models.knowledge_graph import KGNode, KGEdge
|
||||||
|
from app.models.learning import LearningArtifactRecord, SessionRetrospectiveRecord
|
||||||
from app.models.memory import MemorySummary, UserMemory
|
from app.models.memory import MemorySummary, UserMemory
|
||||||
from app.models.brain import (
|
from app.models.brain import (
|
||||||
BrainEvent,
|
BrainEvent,
|
||||||
@@ -20,6 +21,7 @@ from app.models.brain import (
|
|||||||
from app.models.todo import DailyTodo, TodoSource
|
from app.models.todo import DailyTodo, TodoSource
|
||||||
from app.models.reminder import Reminder, ReminderStatus
|
from app.models.reminder import Reminder, ReminderStatus
|
||||||
from app.models.goal import Goal, GoalStatus
|
from app.models.goal import Goal, GoalStatus
|
||||||
|
from app.models.skill import Skill
|
||||||
from app.models.log import Log, LogType, LogLevel
|
from app.models.log import Log, LogType, LogLevel
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
@@ -38,6 +40,8 @@ __all__ = [
|
|||||||
"Message",
|
"Message",
|
||||||
"KGNode",
|
"KGNode",
|
||||||
"KGEdge",
|
"KGEdge",
|
||||||
|
"LearningArtifactRecord",
|
||||||
|
"SessionRetrospectiveRecord",
|
||||||
"MemorySummary",
|
"MemorySummary",
|
||||||
"UserMemory",
|
"UserMemory",
|
||||||
"BrainEvent",
|
"BrainEvent",
|
||||||
@@ -53,6 +57,7 @@ __all__ = [
|
|||||||
"ReminderStatus",
|
"ReminderStatus",
|
||||||
"Goal",
|
"Goal",
|
||||||
"GoalStatus",
|
"GoalStatus",
|
||||||
|
"Skill",
|
||||||
"Log",
|
"Log",
|
||||||
"LogType",
|
"LogType",
|
||||||
"LogLevel",
|
"LogLevel",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from sqlalchemy import Column, String, Text, Boolean, JSON, ForeignKey
|
from sqlalchemy import Column, String, Text, Boolean, JSON, ForeignKey, Float, Integer, DateTime
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
from app.models.base import BaseModel
|
from app.models.base import BaseModel
|
||||||
|
|
||||||
@@ -17,6 +17,14 @@ class Skill(BaseModel):
|
|||||||
is_builtin = Column(Boolean, default=False, nullable=False)
|
is_builtin = Column(Boolean, default=False, nullable=False)
|
||||||
team_id = Column(String(36), ForeignKey("users.id"), nullable=True)
|
team_id = Column(String(36), ForeignKey("users.id"), nullable=True)
|
||||||
is_active = Column(Boolean, default=True)
|
is_active = Column(Boolean, default=True)
|
||||||
|
status = Column(String(20), default="active", nullable=False, index=True) # candidate/shadow/active/deprecated/retired
|
||||||
|
scope = Column(JSON, default=list, nullable=False)
|
||||||
|
effectiveness = Column(Float, default=0.0, nullable=False)
|
||||||
|
review_after = Column(DateTime, nullable=True)
|
||||||
|
candidate_count = Column(Integer, default=0, nullable=False)
|
||||||
|
candidate_source_hashes = Column(JSON, default=list, nullable=False)
|
||||||
|
activation_count = Column(Integer, default=0, nullable=False)
|
||||||
|
last_activated_at = Column(DateTime, nullable=True)
|
||||||
owner_id = Column(String(36), ForeignKey("users.id"), nullable=False)
|
owner_id = Column(String(36), ForeignKey("users.id"), nullable=False)
|
||||||
|
|
||||||
owner = relationship("User", foreign_keys=[owner_id])
|
owner = relationship("User", foreign_keys=[owner_id])
|
||||||
|
|||||||
BIN
data/jarvis.db
BIN
data/jarvis.db
Binary file not shown.
Reference in New Issue
Block a user