hyperforge 1.0.0.post80__tar.gz → 1.0.0.post116__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 (105) hide show
  1. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/PKG-INFO +1 -1
  2. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/pyproject.toml +1 -1
  3. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/session.py +21 -5
  4. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/broker/redis.py +76 -16
  5. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/server/session.py +1 -1
  6. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/server/settings.py +2 -0
  7. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/README.md +0 -0
  8. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/VERSION +0 -0
  9. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/__init__.py +0 -0
  10. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/agent.py +0 -0
  11. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/alembic/README +0 -0
  12. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/alembic/env.py +0 -0
  13. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/alembic/script.py.mako +0 -0
  14. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/alembic/versions/049a4aed19e1_create_generation_table.py +0 -0
  15. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/alembic/versions/1416cb41bd49_add_downloads_table.py +0 -0
  16. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/alembic/versions/2847934e2d59_unique_driver.py +0 -0
  17. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/alembic/versions/4d89a36c8bda_memory.py +0 -0
  18. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/alembic/versions/72b997edb05d_identifier_for_drivers.py +0 -0
  19. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/alembic/versions/9c6f6a1b4e7f_workflows_default_fk.py +0 -0
  20. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/alembic/versions/b8edb72295e0_.py +0 -0
  21. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/alembic/versions/f3d2c1b0a9e8_soft_delete_workflows.py +0 -0
  22. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/alembic.ini +0 -0
  23. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/__init__.py +0 -0
  24. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/app.py +0 -0
  25. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/authentication.py +0 -0
  26. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/commands.py +0 -0
  27. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/internal/__init__.py +0 -0
  28. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/internal/inspect.py +0 -0
  29. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/internal/router.py +0 -0
  30. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/logging.py +0 -0
  31. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/models.py +0 -0
  32. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/settings.py +0 -0
  33. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/utils.py +0 -0
  34. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/v1/__init__.py +0 -0
  35. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/v1/agents.py +0 -0
  36. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/v1/interaction.py +0 -0
  37. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/v1/mcp_content.py +0 -0
  38. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/v1/mcp_interaction.py +0 -0
  39. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/v1/oauth.py +1 -1
  40. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/v1/prompt.py +0 -0
  41. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/v1/router.py +0 -0
  42. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/v1/schema.py +0 -0
  43. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/v1/session.py +0 -0
  44. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/v1/utils.py +0 -0
  45. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/api/v1/workflows.py +0 -0
  46. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/arag.py +0 -0
  47. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/broker/__init__.py +0 -0
  48. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/broker/local.py +0 -0
  49. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/configure.py +0 -0
  50. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/context/__init__.py +0 -0
  51. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/context/agent.py +0 -0
  52. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/context/config.py +0 -0
  53. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/database.py +0 -0
  54. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/db/__init__.py +0 -0
  55. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/db/agents.py +0 -0
  56. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/db/encryption.py +0 -0
  57. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/db/exceptions.py +0 -0
  58. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/db/settings.py +0 -0
  59. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/db/workflow_cleanup.py +0 -0
  60. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/definition.py +0 -0
  61. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/driver.py +0 -0
  62. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/dummy.py +0 -0
  63. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/engine.py +0 -0
  64. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/exceptions.py +0 -0
  65. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/feature_flag.py +0 -0
  66. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/fixtures.py +0 -0
  67. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/interaction.py +0 -0
  68. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/llm.py +0 -0
  69. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/manager.py +0 -0
  70. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/memory/__init__.py +0 -0
  71. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/memory/memory.py +0 -0
  72. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/minimal_fixtures.py +0 -0
  73. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/models.py +0 -0
  74. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/nua.py +0 -0
  75. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/openapi.py +0 -0
  76. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/prompts.py +0 -0
  77. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/pubsub.py +0 -0
  78. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/py.typed +0 -0
  79. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/redis_utils.py +0 -0
  80. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/retrieval/__init__.py +0 -0
  81. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/retrieval/agent.py +0 -0
  82. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/retrieval/config.py +0 -0
  83. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/server/__init__.py +0 -0
  84. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/server/cache.py +0 -0
  85. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/server/run.py +0 -0
  86. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/server/sandbox.py +1 -1
  87. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/server/utils.py +0 -0
  88. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/server/web.py +0 -0
  89. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/settings.py +0 -0
  90. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/standalone/__init__.py +0 -0
  91. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/standalone/agent.py +0 -0
  92. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/standalone/app.py +0 -0
  93. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/standalone/config.py +0 -0
  94. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/standalone/const.py +0 -0
  95. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/standalone/run.py +0 -0
  96. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/standalone/settings.py +0 -0
  97. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/standalone/ui_router.py +0 -0
  98. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/static/assets/index-DLejS5jC.js +0 -0
  99. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/static/assets/index-MoxkZ1_3.css +0 -0
  100. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/static/favicon.svg +0 -0
  101. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/static/index.html +0 -0
  102. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/trace.py +0 -0
  103. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/utils/__init__.py +0 -0
  104. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/utils/http.py +0 -0
  105. {hyperforge-1.0.0.post80 → hyperforge-1.0.0.post116}/src/hyperforge/workflows.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperforge
3
- Version: 1.0.0.post80
3
+ Version: 1.0.0.post116
4
4
  Summary: Agentic Framework for Orchestrated Runtime, Governance, and Execution
5
5
  Author: AI Data Team
6
6
  Author-email: AI Data Team <learning@nuclia.com>
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "hyperforge"
7
- version = "1.0.0.post80"
7
+ version = "1.0.0.post116"
8
8
  authors = [{ name = "AI Data Team", email = "learning@nuclia.com" }]
9
9
  description = "Agentic Framework for Orchestrated Runtime, Governance, and Execution"
10
10
  readme = "README.md"
@@ -1,5 +1,6 @@
1
1
  """Session management functions for ARAG agents with NucliaDB memory."""
2
2
 
3
+ from uuid import UUID
3
4
  from typing import Optional
4
5
 
5
6
  from nucliadb_models import (
@@ -19,6 +20,14 @@ from hyperforge.api.models import INFO_FIELD_ID
19
20
  from hyperforge.memory.memory import QUESTION_ANSWERS_FIELD
20
21
 
21
22
 
23
+ def _is_uuid(value: str) -> bool:
24
+ try:
25
+ UUID(value)
26
+ return True
27
+ except (ValueError, TypeError):
28
+ return False
29
+
30
+
22
31
  async def create_session_resource(
23
32
  ndb: NucliaDBAsync,
24
33
  agent_id: str,
@@ -110,11 +119,18 @@ async def session_exists(
110
119
  True if session exists, False otherwise
111
120
  """
112
121
  try:
113
- await ndb.get_resource_by_id(
114
- rid=session_id,
115
- kbid=agent_id,
116
- query_params={"show": ["basic"]},
117
- )
122
+ if _is_uuid(session_id):
123
+ await ndb.get_resource_by_id(
124
+ rid=session_id,
125
+ kbid=agent_id,
126
+ query_params={"show": ["basic"]},
127
+ )
128
+ else:
129
+ await ndb.get_resource_by_slug(
130
+ slug=session_id,
131
+ kbid=agent_id,
132
+ query_params={"show": ["basic"]},
133
+ )
118
134
  return True
119
135
  except NotFoundError:
120
136
  return False
@@ -1,10 +1,14 @@
1
1
  import asyncio
2
2
  import json
3
- from typing import AsyncIterator, cast
3
+ import time
4
+ from typing import Any, AsyncIterator, cast
4
5
 
5
6
  import opentelemetry.propagate
6
7
  from pydantic import TypeAdapter
7
8
  from redis.asyncio import Redis, ResponseError
9
+ from redis.asyncio.retry import Retry
10
+ from redis.backoff import ExponentialBackoff
11
+ from redis.exceptions import ConnectionError as RedisConnectionError
8
12
 
9
13
  from hyperforge import logger
10
14
  from hyperforge.broker import AgentTimeoutError, Broker
@@ -12,6 +16,15 @@ from hyperforge.pubsub import AgentMessage, StartInteraction
12
16
  from hyperforge.redis_utils import ManualStreamKeysRedisCluster
13
17
 
14
18
 
19
+ _REDIS_CONNECT_TIMEOUT_SECONDS = 5
20
+ _REDIS_HEALTH_CHECK_INTERVAL_SECONDS = 30
21
+ _REDIS_RETRY_ATTEMPTS = 3
22
+ _REDIS_RETRY_BACKOFF_BASE_SECONDS = 0.1
23
+ _REDIS_RETRY_BACKOFF_CAP_SECONDS = 1.0
24
+ _REDIS_SUBSCRIBE_ACTIVATIONS_RETRY_SLEEP_SECONDS = 1
25
+ _REPLY_READ_BLOCK_MAX_MS = 2000
26
+
27
+
15
28
  class RedisBroker(Broker):
16
29
  def __init__(self, client: Redis, activate_subject: str, keepalive_ms: int):
17
30
  self._client = client
@@ -30,23 +43,42 @@ class RedisBroker(Broker):
30
43
  keepalive_ms: int,
31
44
  cluster_mode: bool = False,
32
45
  ) -> "RedisBroker":
46
+ client_kwargs = cls._client_kwargs(keepalive_ms)
33
47
  if cluster_mode:
34
48
  client = cast(
35
49
  Redis,
36
50
  ManualStreamKeysRedisCluster.from_url(
37
51
  url=url,
38
- decode_responses=True,
39
52
  dynamic_startup_nodes=False,
53
+ **client_kwargs,
40
54
  ),
41
55
  )
42
56
  else:
43
57
  client = Redis.from_url(
44
58
  url,
45
- decode_responses=True,
46
- socket_timeout=keepalive_ms / 1000,
47
- )
59
+ **client_kwargs,
60
+ ) # type: ignore[call-overload]
48
61
  return cls(client, activate_subject, keepalive_ms)
49
62
 
63
+ @staticmethod
64
+ def _client_kwargs(keepalive_ms: int) -> dict[str, Any]:
65
+ retry = Retry(
66
+ backoff=ExponentialBackoff(
67
+ base=_REDIS_RETRY_BACKOFF_BASE_SECONDS,
68
+ cap=_REDIS_RETRY_BACKOFF_CAP_SECONDS,
69
+ ),
70
+ retries=_REDIS_RETRY_ATTEMPTS,
71
+ )
72
+ return {
73
+ "decode_responses": True,
74
+ "socket_timeout": keepalive_ms / 1000,
75
+ "socket_connect_timeout": _REDIS_CONNECT_TIMEOUT_SECONDS,
76
+ "health_check_interval": _REDIS_HEALTH_CHECK_INTERVAL_SECONDS,
77
+ "socket_keepalive": True,
78
+ "retry": retry,
79
+ "retry_on_timeout": True,
80
+ }
81
+
50
82
  async def publish_activation(
51
83
  self, msg: StartInteraction, trace: dict[str, str]
52
84
  ) -> None:
@@ -99,11 +131,15 @@ class RedisBroker(Broker):
99
131
  logger.warning("Consumer group lost, re-creating...")
100
132
  await self._ensure_consumer_group()
101
133
  else:
102
- logger.exception("Error while subscribing to activations, retrying...")
103
- await asyncio.sleep(1)
134
+ logger.exception(
135
+ "Error while subscribing to activations, retrying..."
136
+ )
137
+ await asyncio.sleep(
138
+ _REDIS_SUBSCRIBE_ACTIVATIONS_RETRY_SLEEP_SECONDS
139
+ )
104
140
  except Exception:
105
141
  logger.exception("Error while subscribing to activations, retrying...")
106
- await asyncio.sleep(1)
142
+ await asyncio.sleep(_REDIS_SUBSCRIBE_ACTIVATIONS_RETRY_SLEEP_SECONDS)
107
143
 
108
144
  async def publish(self, topic: str, message: AgentMessage) -> None:
109
145
  async with self._client.pipeline() as pipe:
@@ -157,14 +193,38 @@ class RedisBroker(Broker):
157
193
  )
158
194
 
159
195
  async def receive_reply(self, key: str, timeout_ms: int) -> str | None:
160
- response = await self._client.xread(
161
- {key: "$"},
162
- block=timeout_ms,
163
- count=1,
164
- )
165
- if not response:
166
- return None
167
- return response[0][1][0][1]["msg"]
196
+ deadline = time.monotonic() + (timeout_ms / 1000)
197
+ reconnect_attempts = 0
198
+
199
+ while True:
200
+ remaining_s = deadline - time.monotonic()
201
+ if remaining_s <= 0:
202
+ return None
203
+
204
+ # Keep each blocking read short so transient socket closures/failovers
205
+ # can be recovered within the same overall timeout budget.
206
+ block_ms = min(_REPLY_READ_BLOCK_MAX_MS, max(1, int(remaining_s * 1000)))
207
+
208
+ try:
209
+ response = await self._client.xread(
210
+ {key: "$"},
211
+ block=block_ms,
212
+ count=1,
213
+ )
214
+ except RedisConnectionError:
215
+ reconnect_attempts += 1
216
+ backoff_s = min(1.0, 0.1 * reconnect_attempts)
217
+ logger.warning(
218
+ "Redis connection closed while receiving reply key=%s; retrying (attempt=%d)",
219
+ key,
220
+ reconnect_attempts,
221
+ )
222
+ await asyncio.sleep(backoff_s)
223
+ continue
224
+
225
+ if not response:
226
+ continue
227
+ return response[0][1][0][1]["msg"]
168
228
 
169
229
  async def initialize(self) -> None:
170
230
  pass
@@ -111,7 +111,7 @@ class SessionManager:
111
111
  logger.error(f"Module {load_module} could not be loaded")
112
112
 
113
113
  self.activation_task = asyncio.create_task(self.activation_listener())
114
- if health_check:
114
+ if health_check and self.settings.health_check_enabled:
115
115
  self.server = await start_health_check()
116
116
 
117
117
  async def finalize(self):
@@ -45,3 +45,5 @@ class Settings(BaseSettings):
45
45
  # the kbid for internal NUA calls from the account_id request header
46
46
  # instead.
47
47
  standalone: bool = False
48
+
49
+ health_check_enabled: bool = True
@@ -3,13 +3,13 @@ from urllib.parse import urlencode
3
3
 
4
4
  from cryptography.fernet import InvalidToken
5
5
  from fastapi import Query
6
+ from hyperforge_mcp.http import _fingerprint, decrypt_mcp_oauth_state
6
7
  from starlette.requests import Request
7
8
  from starlette.responses import HTMLResponse
8
9
 
9
10
  from hyperforge.api.settings import Settings
10
11
  from hyperforge.api.v1.router import router
11
12
  from hyperforge.api.v1.utils import tracer
12
- from hyperforge_mcp.http import _fingerprint, decrypt_mcp_oauth_state
13
13
 
14
14
  logger = logging.getLogger(__name__)
15
15
 
@@ -2,12 +2,12 @@ import asyncio
2
2
  from importlib.metadata import version
3
3
 
4
4
  import sentry_sdk
5
+ from hyperforge_restricted import sandbox
5
6
  from nucliadb_telemetry.fastapi import application_metrics
6
7
  from nucliadb_telemetry.logs import setup_logging
7
8
  from nucliadb_telemetry.settings import LogLevel, LogSettings
8
9
  from sentry_sdk.integrations.excepthook import ExcepthookIntegration
9
10
 
10
- from hyperforge_restricted import sandbox
11
11
  from hyperforge.server.settings import Settings
12
12
 
13
13