hyperforge 1.0.0.post19__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. hyperforge-1.0.0.post19/PKG-INFO +95 -0
  2. hyperforge-1.0.0.post19/README.md +54 -0
  3. hyperforge-1.0.0.post19/pyproject.toml +85 -0
  4. hyperforge-1.0.0.post19/setup.cfg +4 -0
  5. hyperforge-1.0.0.post19/src/hyperforge/__init__.py +16 -0
  6. hyperforge-1.0.0.post19/src/hyperforge/agent.py +81 -0
  7. hyperforge-1.0.0.post19/src/hyperforge/api/__init__.py +20 -0
  8. hyperforge-1.0.0.post19/src/hyperforge/api/app.py +155 -0
  9. hyperforge-1.0.0.post19/src/hyperforge/api/authentication.py +271 -0
  10. hyperforge-1.0.0.post19/src/hyperforge/api/commands.py +33 -0
  11. hyperforge-1.0.0.post19/src/hyperforge/api/internal/__init__.py +4 -0
  12. hyperforge-1.0.0.post19/src/hyperforge/api/internal/inspect.py +30 -0
  13. hyperforge-1.0.0.post19/src/hyperforge/api/internal/router.py +3 -0
  14. hyperforge-1.0.0.post19/src/hyperforge/api/logging.py +18 -0
  15. hyperforge-1.0.0.post19/src/hyperforge/api/models.py +129 -0
  16. hyperforge-1.0.0.post19/src/hyperforge/api/session.py +197 -0
  17. hyperforge-1.0.0.post19/src/hyperforge/api/settings.py +38 -0
  18. hyperforge-1.0.0.post19/src/hyperforge/api/utils.py +354 -0
  19. hyperforge-1.0.0.post19/src/hyperforge/api/v1/__init__.py +23 -0
  20. hyperforge-1.0.0.post19/src/hyperforge/api/v1/agents.py +531 -0
  21. hyperforge-1.0.0.post19/src/hyperforge/api/v1/interaction.py +430 -0
  22. hyperforge-1.0.0.post19/src/hyperforge/api/v1/mcp_content.py +311 -0
  23. hyperforge-1.0.0.post19/src/hyperforge/api/v1/mcp_interaction.py +322 -0
  24. hyperforge-1.0.0.post19/src/hyperforge/api/v1/oauth.py +60 -0
  25. hyperforge-1.0.0.post19/src/hyperforge/api/v1/prompt.py +129 -0
  26. hyperforge-1.0.0.post19/src/hyperforge/api/v1/router.py +3 -0
  27. hyperforge-1.0.0.post19/src/hyperforge/api/v1/schema.py +56 -0
  28. hyperforge-1.0.0.post19/src/hyperforge/api/v1/session.py +182 -0
  29. hyperforge-1.0.0.post19/src/hyperforge/api/v1/utils.py +12 -0
  30. hyperforge-1.0.0.post19/src/hyperforge/api/v1/workflows.py +643 -0
  31. hyperforge-1.0.0.post19/src/hyperforge/arag.py +28 -0
  32. hyperforge-1.0.0.post19/src/hyperforge/broker/__init__.py +52 -0
  33. hyperforge-1.0.0.post19/src/hyperforge/broker/local.py +116 -0
  34. hyperforge-1.0.0.post19/src/hyperforge/broker/redis.py +161 -0
  35. hyperforge-1.0.0.post19/src/hyperforge/configure.py +571 -0
  36. hyperforge-1.0.0.post19/src/hyperforge/context/__init__.py +0 -0
  37. hyperforge-1.0.0.post19/src/hyperforge/context/agent.py +377 -0
  38. hyperforge-1.0.0.post19/src/hyperforge/context/config.py +103 -0
  39. hyperforge-1.0.0.post19/src/hyperforge/database.py +3 -0
  40. hyperforge-1.0.0.post19/src/hyperforge/db/__init__.py +6 -0
  41. hyperforge-1.0.0.post19/src/hyperforge/db/agents.py +1521 -0
  42. hyperforge-1.0.0.post19/src/hyperforge/db/encryption.py +91 -0
  43. hyperforge-1.0.0.post19/src/hyperforge/db/exceptions.py +26 -0
  44. hyperforge-1.0.0.post19/src/hyperforge/db/settings.py +16 -0
  45. hyperforge-1.0.0.post19/src/hyperforge/db/workflow_cleanup.py +69 -0
  46. hyperforge-1.0.0.post19/src/hyperforge/definition.py +13 -0
  47. hyperforge-1.0.0.post19/src/hyperforge/driver.py +31 -0
  48. hyperforge-1.0.0.post19/src/hyperforge/dummy.py +28 -0
  49. hyperforge-1.0.0.post19/src/hyperforge/engine.py +189 -0
  50. hyperforge-1.0.0.post19/src/hyperforge/exceptions.py +14 -0
  51. hyperforge-1.0.0.post19/src/hyperforge/feature_flag.py +105 -0
  52. hyperforge-1.0.0.post19/src/hyperforge/fixtures.py +602 -0
  53. hyperforge-1.0.0.post19/src/hyperforge/interaction.py +116 -0
  54. hyperforge-1.0.0.post19/src/hyperforge/llm.py +75 -0
  55. hyperforge-1.0.0.post19/src/hyperforge/manager.py +432 -0
  56. hyperforge-1.0.0.post19/src/hyperforge/memory/__init__.py +5 -0
  57. hyperforge-1.0.0.post19/src/hyperforge/memory/memory.py +974 -0
  58. hyperforge-1.0.0.post19/src/hyperforge/minimal_fixtures.py +75 -0
  59. hyperforge-1.0.0.post19/src/hyperforge/models.py +336 -0
  60. hyperforge-1.0.0.post19/src/hyperforge/nua.py +336 -0
  61. hyperforge-1.0.0.post19/src/hyperforge/openapi.py +63 -0
  62. hyperforge-1.0.0.post19/src/hyperforge/prompts.py +188 -0
  63. hyperforge-1.0.0.post19/src/hyperforge/pubsub.py +90 -0
  64. hyperforge-1.0.0.post19/src/hyperforge/py.typed +0 -0
  65. hyperforge-1.0.0.post19/src/hyperforge/redis_utils.py +82 -0
  66. hyperforge-1.0.0.post19/src/hyperforge/retrieval/__init__.py +0 -0
  67. hyperforge-1.0.0.post19/src/hyperforge/retrieval/agent.py +169 -0
  68. hyperforge-1.0.0.post19/src/hyperforge/retrieval/config.py +94 -0
  69. hyperforge-1.0.0.post19/src/hyperforge/server/__init__.py +5 -0
  70. hyperforge-1.0.0.post19/src/hyperforge/server/cache.py +131 -0
  71. hyperforge-1.0.0.post19/src/hyperforge/server/run.py +109 -0
  72. hyperforge-1.0.0.post19/src/hyperforge/server/sandbox.py +60 -0
  73. hyperforge-1.0.0.post19/src/hyperforge/server/session.py +421 -0
  74. hyperforge-1.0.0.post19/src/hyperforge/server/settings.py +47 -0
  75. hyperforge-1.0.0.post19/src/hyperforge/server/utils.py +57 -0
  76. hyperforge-1.0.0.post19/src/hyperforge/server/web.py +31 -0
  77. hyperforge-1.0.0.post19/src/hyperforge/settings.py +18 -0
  78. hyperforge-1.0.0.post19/src/hyperforge/standalone/__init__.py +5 -0
  79. hyperforge-1.0.0.post19/src/hyperforge/standalone/agent.py +189 -0
  80. hyperforge-1.0.0.post19/src/hyperforge/standalone/app.py +264 -0
  81. hyperforge-1.0.0.post19/src/hyperforge/standalone/config.py +137 -0
  82. hyperforge-1.0.0.post19/src/hyperforge/standalone/const.py +1 -0
  83. hyperforge-1.0.0.post19/src/hyperforge/standalone/run.py +60 -0
  84. hyperforge-1.0.0.post19/src/hyperforge/standalone/settings.py +133 -0
  85. hyperforge-1.0.0.post19/src/hyperforge/standalone/ui_router.py +241 -0
  86. hyperforge-1.0.0.post19/src/hyperforge/trace.py +42 -0
  87. hyperforge-1.0.0.post19/src/hyperforge/utils/__init__.py +112 -0
  88. hyperforge-1.0.0.post19/src/hyperforge/utils/http.py +48 -0
  89. hyperforge-1.0.0.post19/src/hyperforge/workflows.py +44 -0
  90. hyperforge-1.0.0.post19/src/hyperforge.egg-info/PKG-INFO +95 -0
  91. hyperforge-1.0.0.post19/src/hyperforge.egg-info/SOURCES.txt +96 -0
  92. hyperforge-1.0.0.post19/src/hyperforge.egg-info/dependency_links.txt +1 -0
  93. hyperforge-1.0.0.post19/src/hyperforge.egg-info/entry_points.txt +8 -0
  94. hyperforge-1.0.0.post19/src/hyperforge.egg-info/requires.txt +27 -0
  95. hyperforge-1.0.0.post19/src/hyperforge.egg-info/top_level.txt +1 -0
  96. hyperforge-1.0.0.post19/tests/test_convert_arag_answer.py +573 -0
  97. hyperforge-1.0.0.post19/tests/test_mcp_interaction.py +311 -0
  98. hyperforge-1.0.0.post19/tests/test_next.py +98 -0
@@ -0,0 +1,95 @@
1
+ Metadata-Version: 2.4
2
+ Name: hyperforge
3
+ Version: 1.0.0.post19
4
+ Summary: Agentic Framework for Orchestrated Runtime, Governance, and Execution
5
+ Author-email: AI Data Team <learning@nuclia.com>
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Progress, https://progress.com
8
+ Project-URL: Github, https://github.com/nuclia/forge
9
+ Project-URL: API Reference, https://docs.rag.progress.cloud
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ Requires-Dist: alembic
15
+ Requires-Dist: pydantic
16
+ Requires-Dist: nuclia>=4.9.25
17
+ Requires-Dist: nuclia-models>=0.52.1
18
+ Requires-Dist: nucliadb-models>=6.13.1.post6414
19
+ Requires-Dist: nucliadb-sdk>=6.13.1.post6414
20
+ Requires-Dist: nucliadb-telemetry[otel]
21
+ Requires-Dist: pydantic_settings
22
+ Requires-Dist: mcp>=1.26.0
23
+ Requires-Dist: prometheus_client
24
+ Requires-Dist: mrflagly>=0.2.11
25
+ Requires-Dist: aiodns
26
+ Requires-Dist: httpx
27
+ Requires-Dist: jinja2
28
+ Requires-Dist: databases[asyncpg]
29
+ Requires-Dist: sqlalchemy
30
+ Requires-Dist: cryptography
31
+ Requires-Dist: mmh3
32
+ Requires-Dist: psycopg2
33
+ Requires-Dist: tenacity
34
+ Requires-Dist: websockets
35
+ Requires-Dist: redis[hiredis]>=6.4.0
36
+ Requires-Dist: types-redis>=4.6.0.20241004
37
+ Requires-Dist: ruff>=0.15.10
38
+ Requires-Dist: lru-dict
39
+ Requires-Dist: sentry_sdk
40
+ Requires-Dist: fastapi
41
+
42
+ # Hyperforge
43
+
44
+ Hyperforge is the core agentic workflow framework in this repository. It
45
+ provides the runtime, HTTP API, workflow orchestration, broker integration,
46
+ persistence layer, and support for loading Hyperforge agent packages.
47
+
48
+ ## Install
49
+
50
+ From the workspace root:
51
+
52
+ ```bash
53
+ uv sync
54
+ ```
55
+
56
+ ## Run
57
+
58
+ Start the API service:
59
+
60
+ ```bash
61
+ uv run hyperforge-api
62
+ ```
63
+
64
+ Useful endpoints:
65
+
66
+ - `/health/ready`
67
+ - `/health/alive`
68
+ - `/metrics`
69
+
70
+ ## Configuration
71
+
72
+ Runtime configuration is provided through environment variables consumed by
73
+ Pydantic settings. Common settings include:
74
+
75
+ - `HTTP_HOST` and `HTTP_PORT`
76
+ - `MEMORY_READER_NUCLIADB`, `MEMORY_WRITER_NUCLIADB`, and
77
+ `MEMORY_SEARCH_NUCLIADB`
78
+ - `MEMORY_APIKEY_NUCLIADB`
79
+ - `VALKEY_URL`
80
+ - `LOAD_MODULES`
81
+
82
+ ## Development
83
+
84
+ Run the package tests from the workspace root:
85
+
86
+ ```bash
87
+ uv run pytest hyperforge
88
+ ```
89
+
90
+ Format and lint with the root `Makefile`:
91
+
92
+ ```bash
93
+ make fmt
94
+ make lint
95
+ ```
@@ -0,0 +1,54 @@
1
+ # Hyperforge
2
+
3
+ Hyperforge is the core agentic workflow framework in this repository. It
4
+ provides the runtime, HTTP API, workflow orchestration, broker integration,
5
+ persistence layer, and support for loading Hyperforge agent packages.
6
+
7
+ ## Install
8
+
9
+ From the workspace root:
10
+
11
+ ```bash
12
+ uv sync
13
+ ```
14
+
15
+ ## Run
16
+
17
+ Start the API service:
18
+
19
+ ```bash
20
+ uv run hyperforge-api
21
+ ```
22
+
23
+ Useful endpoints:
24
+
25
+ - `/health/ready`
26
+ - `/health/alive`
27
+ - `/metrics`
28
+
29
+ ## Configuration
30
+
31
+ Runtime configuration is provided through environment variables consumed by
32
+ Pydantic settings. Common settings include:
33
+
34
+ - `HTTP_HOST` and `HTTP_PORT`
35
+ - `MEMORY_READER_NUCLIADB`, `MEMORY_WRITER_NUCLIADB`, and
36
+ `MEMORY_SEARCH_NUCLIADB`
37
+ - `MEMORY_APIKEY_NUCLIADB`
38
+ - `VALKEY_URL`
39
+ - `LOAD_MODULES`
40
+
41
+ ## Development
42
+
43
+ Run the package tests from the workspace root:
44
+
45
+ ```bash
46
+ uv run pytest hyperforge
47
+ ```
48
+
49
+ Format and lint with the root `Makefile`:
50
+
51
+ ```bash
52
+ make fmt
53
+ make lint
54
+ ```
@@ -0,0 +1,85 @@
1
+ [build-system]
2
+ requires = ["setuptools >= 64"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "hyperforge"
7
+ version = "1.0.0.post19"
8
+ authors = [{ name = "AI Data Team", email = "learning@nuclia.com" }]
9
+ description = "Agentic Framework for Orchestrated Runtime, Governance, and Execution"
10
+ readme = "README.md"
11
+ requires-python = ">=3.10"
12
+ classifiers = [
13
+ "Programming Language :: Python :: 3",
14
+ "Operating System :: OS Independent",
15
+ ]
16
+ license = "Apache-2.0"
17
+ dependencies = [
18
+ "alembic",
19
+ "pydantic",
20
+ "nuclia>=4.9.25",
21
+ "nuclia-models>=0.52.1",
22
+ "nucliadb-models>=6.13.1.post6414",
23
+ "nucliadb-sdk>=6.13.1.post6414",
24
+ "nucliadb-telemetry[otel]",
25
+ "pydantic_settings",
26
+ "mcp>=1.26.0",
27
+ "prometheus_client",
28
+ "mrflagly>=0.2.11",
29
+ "aiodns",
30
+ "httpx",
31
+ "jinja2",
32
+ "databases[asyncpg]",
33
+ "sqlalchemy",
34
+ "cryptography",
35
+ "mmh3",
36
+ "psycopg2",
37
+ "tenacity",
38
+ "websockets",
39
+ "redis[hiredis]>=6.4.0",
40
+ "types-redis>=4.6.0.20241004",
41
+ "ruff>=0.15.10",
42
+ "lru-dict",
43
+ "sentry_sdk",
44
+ "fastapi",
45
+ ]
46
+
47
+
48
+ [dependency-groups]
49
+ dev = [
50
+ "pytest",
51
+ "pytest-asyncio",
52
+ "pytest-cov",
53
+ "pytest-mock",
54
+ "pytest-benchmark",
55
+ "pytest-docker-fixtures>=1.4.2",
56
+ "pytest-lazy-fixtures",
57
+ "httpx[http2]",
58
+ "hyperforge_rephrase",
59
+ "inline_snapshot",
60
+ "sqlalchemy_utils",
61
+ ]
62
+
63
+ [tool.setuptools.packages.find]
64
+ where = ["src/"]
65
+
66
+ [tool.setuptools.package-data]
67
+ hyperforge = ["frontend/dist/*"]
68
+
69
+ [project.urls]
70
+ "Progress" = "https://progress.com"
71
+ "Github" = "https://github.com/nuclia/forge"
72
+ "API Reference" = "https://docs.rag.progress.cloud"
73
+
74
+ [tool.pytest.ini_options]
75
+ asyncio_mode = "auto"
76
+
77
+
78
+ [project.scripts]
79
+ hyperforge-api = "hyperforge.api:commands.run"
80
+ hyperforge-server = "hyperforge.server:run.run"
81
+ hyperforge-sandbox = "hyperforge.sandbox:run.run"
82
+ hyperforge-extract-openapi = "hyperforge.api.commands:extract_openapi"
83
+ hyperforge-downloads-cronjob = "hyperforge.downloads.command:run"
84
+ hyperforge-workflows-cleanup-cronjob = "hyperforge.agents.workflow_cleanup:run"
85
+ hyperforge-standalone = "hyperforge.standalone:run.run"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,16 @@
1
+ import logging
2
+
3
+ import fire # type: ignore
4
+ import jinja2
5
+
6
+ # Jinja vulnerability is not a concern since this is used to format a string prompt, not to render HTML
7
+ PROMPT_ENVIRONMENT = jinja2.Environment() # nosemgrep
8
+
9
+
10
+ logger = logging.getLogger("hyperforge")
11
+
12
+
13
+ def cli():
14
+ from hyperforge.arag import ARAG
15
+
16
+ fire.Fire(ARAG)
@@ -0,0 +1,81 @@
1
+ import abc
2
+ import uuid
3
+ from typing import Any, Generic, List, Optional, Self, TypeVar
4
+
5
+ from pydantic import BaseModel, Field
6
+
7
+ from hyperforge.manager import Manager
8
+ from hyperforge.memory.memory import QuestionMemory
9
+ from hyperforge.utils import WidgetType
10
+
11
+
12
+ class AgentConfig(BaseModel):
13
+ id: Optional[str] = Field(default_factory=lambda: str(uuid.uuid4()))
14
+ title: str = "agent"
15
+ rules: Optional[List[str]] = Field(
16
+ default=None,
17
+ title="Agent rules",
18
+ description="List of rules to follow when executing this agent",
19
+ json_schema_extra={
20
+ "widget": WidgetType.NOT_SHOWN,
21
+ },
22
+ )
23
+ max_retries: int = 1
24
+ module: Any = Field(
25
+ ..., title="Agent module", description="Module/type of the agent"
26
+ )
27
+
28
+ def subagent_configure(self, config: dict):
29
+ pass
30
+
31
+
32
+ T_Config = TypeVar("T_Config", bound=AgentConfig)
33
+
34
+
35
+ class Agent(Generic[T_Config]):
36
+ __root_agent__: bool = False
37
+ agent_id: str
38
+ config: T_Config
39
+
40
+ def __init__(self, config: T_Config, agent_id: Optional[str] = None):
41
+ self.config: T_Config = config
42
+ self.agent_id: str = (
43
+ agent_id
44
+ if agent_id is not None
45
+ else config.id
46
+ if hasattr(config, "id") and config.id is not None
47
+ else str(uuid.uuid4())
48
+ )
49
+
50
+ @abc.abstractmethod
51
+ async def inner_from_config(self, config: T_Config, agent_id: Optional[str] = None):
52
+ """Initialize the agent from the config. This is where you should put any
53
+ async initialization code that needs to run when the agent is created.
54
+ """
55
+ pass
56
+
57
+ @classmethod
58
+ async def from_config(
59
+ cls, config: T_Config, agent_id: Optional[str] = None
60
+ ) -> Self:
61
+ instance = cls(config=config, agent_id=agent_id)
62
+ await instance.inner_from_config(config, agent_id)
63
+ return instance
64
+
65
+ def step_title(self, description: str) -> str:
66
+ """Format a step title as '<agent title>: <description>'.
67
+
68
+ Uses the user-configured instance title if set, otherwise falls back to
69
+ the Pydantic model_config title (e.g. 'MCP', 'SQL query') which describes
70
+ the agent type.
71
+ """
72
+ config = self.config # type: ignore[attr-defined]
73
+ title = type(config).model_config.get("title") or config.title # type: ignore[attr-defined]
74
+ return f"{title}: {description}"
75
+
76
+ async def __call__(
77
+ self,
78
+ memory: QuestionMemory,
79
+ manager: Manager,
80
+ ):
81
+ raise NotImplementedError()
@@ -0,0 +1,20 @@
1
+ import logging
2
+
3
+ logger = logging.getLogger("hyperforge.api")
4
+
5
+ SERVICE_NAME = "hyperforge_api"
6
+
7
+
8
+ # Define the filter
9
+ class EndpointFilter(logging.Filter):
10
+ def filter(self, record: logging.LogRecord) -> bool:
11
+ return (
12
+ record.args is not None
13
+ and len(record.args) >= 3
14
+ and record.args[2] # type: ignore
15
+ not in ("/", "/metrics", "/health/alive", "/health/ready")
16
+ )
17
+
18
+
19
+ # Add filter to the logger
20
+ logging.getLogger("uvicorn.access").addFilter(EndpointFilter())
@@ -0,0 +1,155 @@
1
+ from typing import Any, Optional, Tuple
2
+
3
+ import prometheus_client # type: ignore
4
+ from fastapi import APIRouter, FastAPI
5
+ from lru import LRU
6
+ from mcp.server.lowlevel.server import Server as MCPServer
7
+ from mcp.server.streamable_http import (
8
+ StreamableHTTPServerTransport,
9
+ )
10
+ from nucliadb_sdk.v2.sdk import NucliaDBAsync
11
+ from nucliadb_telemetry.logs import setup_logging
12
+ from nucliadb_telemetry.settings import LogLevel, LogSettings
13
+ from nucliadb_telemetry.utils import clean_telemetry, setup_telemetry
14
+ from prometheus_client import CONTENT_TYPE_LATEST # type: ignore
15
+ from starlette.middleware.authentication import AuthenticationMiddleware
16
+ from starlette.responses import PlainTextResponse
17
+
18
+ from hyperforge.api import SERVICE_NAME, internal, logger, v1
19
+ from hyperforge.api.authentication import RaoAuthenticationBackend
20
+ from hyperforge.api.logging import set_sentry
21
+ from hyperforge.api.settings import Settings
22
+ from hyperforge.broker import Broker
23
+ from hyperforge.broker.redis import RedisBroker
24
+ from hyperforge.configure import GLOBAL_REGISTRY, load_all_configurations, scan
25
+ from hyperforge.db.agents import AgentManager
26
+ from hyperforge.db.settings import DataManagerSettings
27
+ from hyperforge.feature_flag import get_flag_service
28
+
29
+ router = APIRouter()
30
+
31
+
32
+ @router.get("/metrics")
33
+ async def serve_metrics(): # pragma: no cover
34
+ output = prometheus_client.exposition.generate_latest()
35
+ return PlainTextResponse(
36
+ output.decode("utf8"), headers={"Content-Type": CONTENT_TYPE_LATEST}
37
+ )
38
+
39
+
40
+ @router.get("/health/ready")
41
+ async def health_ready():
42
+ return {"status": "ok"}
43
+
44
+
45
+ @router.get("/health/alive")
46
+ async def health_alive():
47
+ return {"status": "ok"}
48
+
49
+
50
+ class HTTPApplication(FastAPI):
51
+ agent_manager: AgentManager
52
+ arag_search: NucliaDBAsync
53
+ arag_writer: NucliaDBAsync
54
+ arag_reader: NucliaDBAsync
55
+ broker: Broker
56
+ extra_middlewares: Optional[list[Any]] = None
57
+
58
+ def __init__(
59
+ self,
60
+ settings: Settings,
61
+ data_manager_settings: DataManagerSettings,
62
+ *args,
63
+ **kwargs,
64
+ ):
65
+ super().__init__(*args, **kwargs)
66
+ self.settings = settings
67
+ self.data_manager_settings = data_manager_settings
68
+ self.include_router(internal.router)
69
+ self.include_router(v1.router)
70
+ self.include_router(router)
71
+ self.add_middleware(
72
+ AuthenticationMiddleware,
73
+ backend=RaoAuthenticationBackend(),
74
+ )
75
+ if self.extra_middlewares is not None:
76
+ for extra_middleware in self.extra_middlewares:
77
+ self.add_middleware(extra_middleware)
78
+ self.add_event_handler("startup", self.startup)
79
+ self.add_event_handler("shutdown", self.shutdown)
80
+
81
+ async def startup(self) -> None:
82
+ GLOBAL_REGISTRY.clear()
83
+ await setup_telemetry(SERVICE_NAME)
84
+ setup_logging(
85
+ settings=LogSettings(
86
+ debug=self.settings.debug,
87
+ log_level=LogLevel(self.settings.log_level),
88
+ logger_levels={
89
+ "uvicorn.error": LogLevel.ERROR,
90
+ "nucliadb_telemetry": LogLevel.ERROR,
91
+ "mcp.client.streamable_http": LogLevel.WARNING,
92
+ "mcp.server.lowlevel.server": LogLevel.WARNING,
93
+ "hyperforge.configure": LogLevel.WARNING,
94
+ },
95
+ )
96
+ )
97
+ if self.settings.sentry_url is not None:
98
+ set_sentry(
99
+ self.settings.zone,
100
+ self.settings.running_environment,
101
+ self.settings.sentry_url,
102
+ )
103
+
104
+ get_flag_service() # precache the flag service
105
+
106
+ if self.settings.memory_apikey_nucliadb is None:
107
+ api_key = None
108
+ headers = {"X-NUCLIADB-ROLES": "WRITER;READER"}
109
+ else:
110
+ api_key = self.settings.memory_apikey_nucliadb
111
+ headers = None
112
+
113
+ self.arag_writer = NucliaDBAsync(
114
+ url=self.settings.memory_writer_nucliadb,
115
+ api_key=api_key,
116
+ headers=headers,
117
+ )
118
+ self.arag_reader = NucliaDBAsync(
119
+ url=self.settings.memory_reader_nucliadb,
120
+ api_key=api_key,
121
+ headers=headers,
122
+ )
123
+ self.arag_search = NucliaDBAsync(
124
+ url=self.settings.memory_search_nucliadb,
125
+ api_key=api_key,
126
+ headers=headers,
127
+ )
128
+
129
+ self.broker = RedisBroker.from_url(
130
+ url=self.settings.valkey_url,
131
+ activate_subject=self.settings.activate_subject,
132
+ keepalive_ms=int(self.settings.pubsub_keepalive_seconds * 1000),
133
+ cluster_mode=self.settings.valkey_cluster_mode,
134
+ )
135
+
136
+ self.sses: LRU[Tuple[str, str], StreamableHTTPServerTransport] = LRU(size=100)
137
+ self.mcp_servers: LRU[str, MCPServer] = LRU(size=100)
138
+
139
+ self.agent_manager = await AgentManager.from_settings(
140
+ settings=self.data_manager_settings
141
+ )
142
+ await self.agent_manager.initialize()
143
+
144
+ for load_module in self.settings.load_modules:
145
+ try:
146
+ scan(load_module)
147
+ load_all_configurations(load_module)
148
+ except ImportError:
149
+ logger.error(f"Module {load_module} could not be loaded")
150
+
151
+ async def shutdown(self) -> None:
152
+ await self.agent_manager.finalize()
153
+ await self.broker.finalize()
154
+ await clean_telemetry(SERVICE_NAME)
155
+ GLOBAL_REGISTRY.clear()