Skip to content

Commit 53d9312

Browse files
cursoragentDJLougen
andcommitted
fix(config): wire K8s env vars into HiveStack and API server
HiveConfig.from_env() was never used by hive_api_server.py, so K8s/Helm settings (HIVE_VALIDATE_INPUTS, HIVE_RATE_LIMIT, HIVE_MAX_NODES, HIVE_MAX_CONTENT_BYTES, TTL) had no effect at runtime. - Pass max_memory_nodes to RustBrain.max_nodes - Honor max_content_bytes from config when not overridden - Auto-create RateLimiter when HIVE_RATE_LIMIT > 0 - Accept HIVE_MAX_NODES alias used in deploy manifests - Load HiveConfig.from_env() in the REST API server Regression tests added for env wiring and /route validation. Co-authored-by: Daniel <DJLougen@users.noreply.github.com>
1 parent da5663a commit 53d9312

5 files changed

Lines changed: 80 additions & 3 deletions

File tree

hive/config.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ class HiveConfig:
2929
rate_limit: int = 0 # 0 = disabled
3030
default_ttl_s: float | None = None
3131
max_memory_nodes: int = 10_000
32+
max_content_bytes: int = 1_048_576
3233
jwt_secret: str | None = None
3334
otel_endpoint: str | None = None
3435
prometheus_port: int = 0 # 0 = disabled
@@ -68,6 +69,12 @@ def _parse_bool(raw: str) -> bool:
6869
else:
6970
kwargs[attr] = raw
7071

72+
# K8s/Helm manifests use HIVE_MAX_NODES (not HIVE_MAX_MEMORY_NODES).
73+
if "max_memory_nodes" not in kwargs:
74+
alias = os.environ.get(f"{prefix}MAX_NODES")
75+
if alias is not None:
76+
kwargs["max_memory_nodes"] = int(alias)
77+
7178
return cls(**kwargs)
7279

7380
def validate(self) -> None:
@@ -76,6 +83,8 @@ def validate(self) -> None:
7683
raise ValueError("rate_limit must be >= 0")
7784
if self.max_memory_nodes < 1:
7885
raise ValueError("max_memory_nodes must be >= 1")
86+
if self.max_content_bytes < 1:
87+
raise ValueError("max_content_bytes must be >= 1")
7988

8089
def to_dict(self) -> dict[str, Any]:
8190
"""Return a plain dict (useful for JSON logging)."""

hive/stack.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ def __init__(
147147
validate: bool = False,
148148
config: HiveConfig | None = None,
149149
rate_limiter: RateLimiter | None = None,
150-
max_content_bytes: int = 1_048_576,
150+
max_content_bytes: int | None = None,
151151
circuit_breaker: CircuitBreaker | None = None,
152152
) -> None:
153153
self.config = config or HiveConfig()
@@ -163,12 +163,22 @@ def __init__(
163163
tenant_id=tenant_id,
164164
tenant_isolation=self.config.tenant_isolation,
165165
default_ttl_s=self.config.default_ttl_s,
166+
max_nodes=self.config.max_memory_nodes,
166167
)
167168
self._tenant_id = tenant_id
168169
self._validate = validate or self.config.validate_inputs
169170
self.rate_limiter = rate_limiter
171+
if self.rate_limiter is None and self.config.rate_limit > 0:
172+
self.rate_limiter = RateLimiter(
173+
default_capacity=self.config.rate_limit,
174+
refill_rate=max(self.config.rate_limit / 60.0, 1.0),
175+
)
170176
self.circuit_breaker = circuit_breaker
171-
self._max_content_bytes = max_content_bytes
177+
self._max_content_bytes = (
178+
max_content_bytes
179+
if max_content_bytes is not None
180+
else self.config.max_content_bytes
181+
)
172182
self.telemetry = telemetry
173183
self.feedback = feedback_buffer
174184
self._policy_updater = PolicyUpdater() if feedback_buffer is not None else None

scripts/hive_api_server.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from typing import Any
2424

2525
from hive import HiveStack
26+
from hive.config import HiveConfig
2627
from hive.rule_fast import RuleFastHoneyComb
2728

2829

@@ -39,7 +40,7 @@
3940

4041
if _HAS_FASTAPI:
4142
app = FastAPI(title="Hive Agent Memory", version="0.5.0")
42-
stack = HiveStack(honey_comb=RuleFastHoneyComb())
43+
stack = HiveStack(honey_comb=RuleFastHoneyComb(), config=HiveConfig.from_env())
4344

4445
class RouteRequest(BaseModel):
4546
goal: str = Field(default="")

tests/test_enterprise_config.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,37 @@ def test_config_to_dict():
5454
d = cfg.to_dict()
5555
assert d["rate_limit"] == 100
5656
assert "validate_inputs" in d
57+
58+
59+
def test_from_env_reads_max_nodes_alias():
60+
os.environ["HIVE_MAX_NODES"] = "42"
61+
try:
62+
cfg = HiveConfig.from_env()
63+
assert cfg.max_memory_nodes == 42
64+
finally:
65+
del os.environ["HIVE_MAX_NODES"]
66+
67+
68+
def test_from_env_reads_max_content_bytes():
69+
os.environ["HIVE_MAX_CONTENT_BYTES"] = "2048"
70+
try:
71+
cfg = HiveConfig.from_env()
72+
assert cfg.max_content_bytes == 2048
73+
finally:
74+
del os.environ["HIVE_MAX_CONTENT_BYTES"]
75+
76+
77+
def test_stack_applies_config_memory_and_content_limits():
78+
cfg = HiveConfig(max_memory_nodes=3, max_content_bytes=64)
79+
stack = HiveStack(honey_comb=RuleFastHoneyComb(), config=cfg)
80+
assert stack.brain._max_nodes == 3
81+
assert stack._max_content_bytes == 64
82+
83+
84+
def test_stack_auto_rate_limiter_from_config():
85+
cfg = HiveConfig(rate_limit=1)
86+
stack = HiveStack(honey_comb=RuleFastHoneyComb(), config=cfg)
87+
assert stack.rate_limiter is not None
88+
stack.route({"goal": "first", "available_tools": []})
89+
limited = stack.route({"goal": "second", "available_tools": []})
90+
assert limited.source == "ratelimit"

tests/test_hive_api_server.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,26 @@ def test_ready_returns_200_when_stack_is_healthy():
4141
resp = client.get("/ready")
4242
assert resp.status_code == 200
4343
assert resp.json()["status"] == "ready"
44+
45+
46+
@pytest.mark.skipif(not _HAS_FASTAPI, reason="fastapi not installed")
47+
def test_api_server_applies_validate_inputs_from_env(monkeypatch):
48+
"""K8s sets HIVE_VALIDATE_INPUTS=true; the REST server must honor it."""
49+
from hive import HiveStack
50+
from hive.config import HiveConfig
51+
from hive.rule_fast import RuleFastHoneyComb
52+
53+
monkeypatch.setenv("HIVE_VALIDATE_INPUTS", "true")
54+
# Rebuild stack with fresh env (module-level singleton).
55+
api_server.stack = HiveStack(
56+
honey_comb=RuleFastHoneyComb(),
57+
config=HiveConfig.from_env(),
58+
)
59+
client = TestClient(api_server.app)
60+
resp = client.post("/route", json={"goal": "x", "step": -1, "available_tools": []})
61+
assert resp.status_code == 422
62+
monkeypatch.delenv("HIVE_VALIDATE_INPUTS", raising=False)
63+
api_server.stack = HiveStack(
64+
honey_comb=RuleFastHoneyComb(),
65+
config=HiveConfig.from_env(),
66+
)

0 commit comments

Comments
 (0)