ontology
This commit is contained in:
116
ontology_platform/platform/api/deps.py
Normal file
116
ontology_platform/platform/api/deps.py
Normal file
@@ -0,0 +1,116 @@
|
||||
"""FastAPI dependencies and app lifespan.
|
||||
|
||||
Owns the ToolBox singleton, the compiled LangGraph workflow, and the
|
||||
recursion limit. Construction happens once at app startup; teardown is a
|
||||
no-op because OntoCast tools don't currently expose a close hook.
|
||||
|
||||
Why a module-level holder instead of `app.state`:
|
||||
The /process route is async and may be entered concurrently. A simple
|
||||
dict on `app.state` works, but pulling the ToolBox through a typed
|
||||
dependency function makes the contract explicit and gives every route
|
||||
the same view of "what tools and what workflow are available right now".
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
# Make vendored OntoCast importable. (Same trick as platform/config.py.)
|
||||
_REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
_VENDORED_ONTOCAST = _REPO_ROOT / "vendored" / "ontocast"
|
||||
if str(_VENDORED_ONTOCAST) not in sys.path:
|
||||
sys.path.insert(0, str(_VENDORED_ONTOCAST))
|
||||
|
||||
from langchain_core.runnables import RunnableConfig # noqa: E402
|
||||
from langgraph.graph.state import CompiledStateGraph # noqa: E402
|
||||
|
||||
from ontocast.cli.serve import calculate_recursion_limit # noqa: E402
|
||||
from ontocast.config import ServerConfig # noqa: E402
|
||||
from ontocast.stategraph import create_agent_graph # noqa: E402
|
||||
from ontocast.toolbox import ToolBox # noqa: E402
|
||||
|
||||
import importlib
|
||||
|
||||
platform_config = importlib.import_module("platform.config")
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass
|
||||
class AppContext:
|
||||
"""Immutable holder for objects that live as long as the FastAPI app."""
|
||||
|
||||
settings: "platform_config.PlatformSettings"
|
||||
tools: ToolBox
|
||||
workflow: CompiledStateGraph
|
||||
server_config: ServerConfig
|
||||
recursion_limit: int
|
||||
|
||||
|
||||
_context: AppContext | None = None
|
||||
|
||||
|
||||
async def initialize_app_context(
|
||||
settings: "platform_config.PlatformSettings | None" = None,
|
||||
*,
|
||||
head_chunks: int | None = None,
|
||||
) -> AppContext:
|
||||
"""Build ToolBox + workflow once. Idempotent on repeat calls."""
|
||||
global _context
|
||||
if _context is not None:
|
||||
return _context
|
||||
|
||||
settings = settings or platform_config.load_settings()
|
||||
ontocast_config = platform_config.build_ontocast_config(settings)
|
||||
|
||||
tools = ToolBox(ontocast_config)
|
||||
# OntoCast's ToolBox.initialize is async; do it here so a request doesn't
|
||||
# have to pay the cost.
|
||||
await tools.initialize()
|
||||
|
||||
workflow = create_agent_graph(tools)
|
||||
server_config = ontocast_config.server
|
||||
recursion_limit = calculate_recursion_limit(head_chunks, server_config)
|
||||
|
||||
_context = AppContext(
|
||||
settings=settings,
|
||||
tools=tools,
|
||||
workflow=workflow,
|
||||
server_config=server_config,
|
||||
recursion_limit=recursion_limit,
|
||||
)
|
||||
logger.info(
|
||||
"App context initialized "
|
||||
f"(phase={int(settings.phase)}, backend={settings.storage_backend}, "
|
||||
f"working_dir={settings.working_directory})"
|
||||
)
|
||||
return _context
|
||||
|
||||
|
||||
def get_app_context() -> AppContext:
|
||||
"""FastAPI dependency. Raises clearly if the lifespan never ran."""
|
||||
if _context is None:
|
||||
raise RuntimeError(
|
||||
"AppContext not initialized — the app lifespan must run "
|
||||
"`initialize_app_context()` before serving requests."
|
||||
)
|
||||
return _context
|
||||
|
||||
|
||||
def reset_app_context_for_testing() -> None:
|
||||
"""Test-only: drop the cached context so each test can rebuild it."""
|
||||
global _context
|
||||
_context = None
|
||||
|
||||
|
||||
__all__ = [
|
||||
"AppContext",
|
||||
"RunnableConfig",
|
||||
"get_app_context",
|
||||
"initialize_app_context",
|
||||
"reset_app_context_for_testing",
|
||||
]
|
||||
Reference in New Issue
Block a user