mirror of
https://github.com/hoshikawa2/agent_platform_oci.git
synced 2026-07-09 14:04:19 +00:00
Ajustes na documentação e remanejamento dos folders
This commit is contained in:
1
apps/agent_gateway/app/governance/__init__.py
Normal file
1
apps/agent_gateway/app/governance/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
14
apps/agent_gateway/app/governance/audit.py
Normal file
14
apps/agent_gateway/app/governance/audit.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
logger = logging.getLogger("agent_gateway.governance")
|
||||
|
||||
|
||||
def audit_event(name: str, payload: dict[str, Any]) -> None:
|
||||
safe = dict(payload)
|
||||
if "message" in safe:
|
||||
safe["message_len"] = len(str(safe.pop("message") or ""))
|
||||
logger.info("%s %s", name, json.dumps(safe, ensure_ascii=False, default=str))
|
||||
11
apps/agent_gateway/app/governance/evaluation_hooks.py
Normal file
11
apps/agent_gateway/app/governance/evaluation_hooks.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
class EvaluationHooks:
|
||||
def before_backend_call(self, request_payload: dict[str, Any]) -> dict[str, Any]:
|
||||
return request_payload
|
||||
|
||||
def after_backend_call(self, response_payload: dict[str, Any]) -> dict[str, Any]:
|
||||
return response_payload
|
||||
66
apps/agent_gateway/app/governance/model_policies.py
Normal file
66
apps/agent_gateway/app/governance/model_policies.py
Normal file
@@ -0,0 +1,66 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
class ModelPolicyError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class ModelPolicyResolver:
|
||||
def __init__(self, config: dict[str, Any]):
|
||||
self.config = config or {}
|
||||
|
||||
def resolve_profile(
|
||||
self,
|
||||
*,
|
||||
tenant_id: str,
|
||||
agent_id: str | None,
|
||||
operation: str,
|
||||
requested_profile: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
profiles = self.config.get("profiles", {}) or {}
|
||||
operation_profiles = self.config.get("operation_profiles", {}) or {}
|
||||
|
||||
profile_name = requested_profile or operation_profiles.get(operation) or "default"
|
||||
profile = profiles.get(profile_name)
|
||||
if not profile:
|
||||
raise ModelPolicyError(f"Model profile not found: {profile_name}")
|
||||
|
||||
self._validate_policy(
|
||||
tenant_id=tenant_id,
|
||||
agent_id=agent_id,
|
||||
profile_name=profile_name,
|
||||
profile=profile,
|
||||
)
|
||||
|
||||
return {
|
||||
"profile": profile_name,
|
||||
"provider": profile.get("provider"),
|
||||
"model": profile.get("model"),
|
||||
"parameters": {
|
||||
k: v for k, v in profile.items()
|
||||
if k not in {"provider", "model"}
|
||||
},
|
||||
}
|
||||
|
||||
def _validate_policy(
|
||||
self,
|
||||
*,
|
||||
tenant_id: str,
|
||||
agent_id: str | None,
|
||||
profile_name: str,
|
||||
profile: dict[str, Any],
|
||||
) -> None:
|
||||
policies = self.config.get("policies", {}) or {}
|
||||
tenant_policies = policies.get("tenants", {}) or {}
|
||||
tenant_policy = tenant_policies.get(tenant_id) or tenant_policies.get("default") or {}
|
||||
|
||||
allowed_profiles = tenant_policy.get("allowed_profiles")
|
||||
if allowed_profiles and profile_name not in allowed_profiles:
|
||||
raise ModelPolicyError(f"Profile not allowed for tenant={tenant_id}: {profile_name}")
|
||||
|
||||
allowed_providers = tenant_policy.get("allowed_providers")
|
||||
provider = profile.get("provider")
|
||||
if allowed_providers and provider not in allowed_providers:
|
||||
raise ModelPolicyError(f"Provider not allowed for tenant={tenant_id}: {provider}")
|
||||
35
apps/agent_gateway/app/governance/rate_limit.py
Normal file
35
apps/agent_gateway/app/governance/rate_limit.py
Normal file
@@ -0,0 +1,35 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from collections import defaultdict, deque
|
||||
from typing import Any
|
||||
|
||||
|
||||
class RateLimitExceeded(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class InMemoryRateLimiter:
|
||||
def __init__(self, config: dict[str, Any]):
|
||||
self.config = config or {}
|
||||
self.events: dict[str, deque[float]] = defaultdict(deque)
|
||||
|
||||
def check(self, *, tenant_id: str, agent_id: str | None, channel: str | None) -> None:
|
||||
default_limit = ((self.config.get("default") or {}).get("requests_per_minute")) or 600
|
||||
agent_limits = self.config.get("agents") or {}
|
||||
channel_limits = self.config.get("channels") or {}
|
||||
|
||||
limit = default_limit
|
||||
if agent_id and agent_id in agent_limits:
|
||||
limit = agent_limits[agent_id].get("requests_per_minute", limit)
|
||||
if channel and channel in channel_limits:
|
||||
limit = min(limit, channel_limits[channel].get("requests_per_minute", limit))
|
||||
|
||||
key = f"{tenant_id}:{agent_id or '*'}:{channel or '*'}"
|
||||
now = time.time()
|
||||
bucket = self.events[key]
|
||||
while bucket and bucket[0] < now - 60:
|
||||
bucket.popleft()
|
||||
if len(bucket) >= int(limit):
|
||||
raise RateLimitExceeded(f"Gateway rate limit exceeded for {key}: {limit}/min")
|
||||
bucket.append(now)
|
||||
14
apps/agent_gateway/app/governance/usage.py
Normal file
14
apps/agent_gateway/app/governance/usage.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
|
||||
class UsageRecorder:
|
||||
def record_gateway_request(self, payload: dict[str, Any]) -> None:
|
||||
return None
|
||||
|
||||
def record_model_policy(self, payload: dict[str, Any]) -> None:
|
||||
return None
|
||||
|
||||
def record_backend_response(self, payload: dict[str, Any]) -> None:
|
||||
return None
|
||||
Reference in New Issue
Block a user