Enhance MCP development features and introduce skills management

- Added configuration options for requiring human approval before applying LLM-generated MCP patches.
- Updated Docker setup to include skills directory.
- Integrated skills management into the backend, allowing for procedural guides and skill matching.
- Refactored database initialization to apply Alembic migrations.
- Enhanced task approval process to handle MCP patch applications with optional approval.
- Introduced new schemas for skills and updated existing APIs to support skills functionality.

This commit lays the groundwork for improved agent capabilities and better management of MCP development processes.
This commit is contained in:
2026-06-14 22:27:24 +03:00
parent 6185b9b85a
commit 0375b20bb4
30 changed files with 1733 additions and 151 deletions

View File

@@ -1,13 +1,18 @@
"""Async SQLAlchemy engine, session factory, and Base model."""
"""Database schema migrations via Alembic."""
from __future__ import annotations
import asyncio
import logging
from collections.abc import AsyncGenerator
from pathlib import Path
from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
from sqlalchemy.orm import DeclarativeBase
from app.config import settings
logger = logging.getLogger(__name__)
engine = create_async_engine(settings.database_url, echo=False, pool_pre_ping=True)
SessionLocal = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
@@ -21,45 +26,19 @@ async def get_db() -> AsyncGenerator[AsyncSession, None]:
yield session
async def init_db() -> None:
"""Create tables and apply lightweight dev migrations."""
from app import models # noqa: F401
from sqlalchemy import text
def _run_alembic_upgrade() -> None:
from alembic import command
from alembic.config import Config
async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
# Dev migration: locations → vessels (rename legacy table/columns)
await conn.execute(
text(
"""
DO $$
BEGIN
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'locations')
AND NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'vessels')
THEN
ALTER TABLE locations RENAME TO vessels;
END IF;
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'devices' AND column_name = 'location_id')
THEN
ALTER TABLE devices RENAME COLUMN location_id TO vessel_id;
END IF;
IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'tasks' AND column_name = 'location_id')
THEN
ALTER TABLE tasks RENAME COLUMN location_id TO vessel_id;
END IF;
IF NOT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'devices' AND column_name = 'catalog_key')
THEN
ALTER TABLE devices ADD COLUMN catalog_key VARCHAR(64);
END IF;
END $$;
"""
)
)
# Indexes for hot query paths (idempotent; covers pre-existing DBs).
for stmt in (
"CREATE INDEX IF NOT EXISTS ix_tasks_vessel_id ON tasks (vessel_id)",
"CREATE INDEX IF NOT EXISTS ix_task_events_task_id_id ON task_events (task_id, id)",
"CREATE INDEX IF NOT EXISTS ix_approval_requests_task_status "
"ON approval_requests (task_id, status)",
):
await conn.execute(text(stmt))
ini = Path(__file__).resolve().parent.parent / "alembic.ini"
cfg = Config(str(ini))
command.upgrade(cfg, "head")
async def init_db() -> None:
"""Apply Alembic migrations to head."""
try:
await asyncio.to_thread(_run_alembic_upgrade)
except Exception as exc: # noqa: BLE001
logger.exception("Database migration failed")
raise RuntimeError("Database migration failed") from exc