feat: add admin panel

This commit is contained in:
hh
2026-05-20 13:00:08 +02:00
parent 7970d4be9b
commit 0128191ac3
26 changed files with 2985 additions and 115 deletions
+23 -4
View File
@@ -40,6 +40,7 @@ from beaver_gateway.core.registry import AgentRegistry, McpRegistry
from beaver_gateway.frontends.base import GatewayRuntime
from beaver_gateway.mcp.internal_app import build_internal_app
from beaver_gateway.settings import Settings
from beaver_gateway.storage import Database
if TYPE_CHECKING:
from starlette.applications import Starlette
@@ -65,9 +66,24 @@ async def _async_main() -> None:
agents = AgentRegistry(gateway.agents)
mcps = McpRegistry(gateway.mcps)
token_store = TokenStore.from_env(settings.bootstrap_tokens)
# Phase 4.1 — open the async DB and run create_all once. Engine
# pool is process-wide; ``dispose()`` after the TaskGroup unwinds.
db = Database(settings.database_url)
await db.create_all()
# Phase 4.2 — TokenStore now reads from the DB (in-memory cache
# primed at start, TTL-refreshed, last_used_at flushed by a
# background task). BOOTSTRAP_TOKENS layers on top so first-run /
# examples still work without DB writes.
token_store = TokenStore(
db, bootstrap=TokenStore.parse_bootstrap(settings.bootstrap_tokens)
)
async with AsyncExitStack() as stack:
stack.push_async_callback(db.dispose)
await token_store.start()
stack.push_async_callback(token_store.stop)
# Internal MCP URLs must exist before we construct any
# ClaudeCodeBackendAdapter — adapters bake the URLs into their
# ``BackendOptions.mcp_servers`` at construction time.
@@ -87,7 +103,12 @@ async def _async_main() -> None:
mcps=mcps,
backends=backends,
token_store=token_store,
db=db,
mcp_internal_urls=internal_urls,
admin_user=settings.admin_user,
admin_pass=settings.admin_pass,
session_secret=settings.session_secret,
frontends=tuple(gateway.frontends),
)
for fe in gateway.frontends:
@@ -115,9 +136,7 @@ async def _async_main() -> None:
async with asyncio.TaskGroup() as tg:
if internal_app is not None:
tg.create_task(
_serve_internal_mcp(internal_app, settings=settings)
)
tg.create_task(_serve_internal_mcp(internal_app, settings=settings))
for fe in gateway.frontends:
tg.create_task(fe.serve())