124 lines
4.3 KiB
Python
124 lines
4.3 KiB
Python
"""InvalidateCacheTool -- clear validation cache for a subject.
|
|
|
|
Wraps the KV API ``/api/truth/subjects/:subject/invalidate`` endpoint,
|
|
which clears all cached validation results for a specific subject
|
|
(e.g., "economics", "terminology", "safety").
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
from typing import Any, ClassVar
|
|
|
|
import httpx
|
|
|
|
from ..base import Tool, ToolParameter, ToolResult
|
|
|
|
# Read from KV_API_URL environment variable, fallback to localhost
|
|
_DEFAULT_KV_API_URL = os.environ.get("KV_API_URL", "http://localhost:41233")
|
|
_REQUEST_TIMEOUT = 30.0
|
|
|
|
|
|
class InvalidateCacheTool(Tool):
|
|
"""Clear validation cache for a specific subject.
|
|
|
|
Forces revalidation of all content related to a subject by clearing
|
|
the cache. Use this after updating documentation for a subject to ensure
|
|
that subsequent validations reflect the latest knowledge.
|
|
"""
|
|
|
|
name: ClassVar[str] = "invalidate_cache"
|
|
description: ClassVar[str] = (
|
|
"Clear validation cache for a specific subject (e.g., 'economics', "
|
|
"'terminology', 'safety'). Forces fresh validation on next check. "
|
|
"Use this after updating documentation to ensure validations reflect "
|
|
"the latest knowledge base state."
|
|
)
|
|
parameters: ClassVar[list[ToolParameter]] = [
|
|
ToolParameter(
|
|
name="subject",
|
|
type="string",
|
|
description=(
|
|
"Subject identifier to invalidate (e.g., 'economics', 'terminology', "
|
|
"'safety', 'competitors', 'jurisdiction'). Matches the subject "
|
|
"categories used in content validation."
|
|
),
|
|
),
|
|
ToolParameter(
|
|
name="kv_api_url",
|
|
type="string",
|
|
description="KV API base URL",
|
|
required=False,
|
|
default=_DEFAULT_KV_API_URL,
|
|
),
|
|
]
|
|
|
|
async def execute(self, **kwargs: Any) -> ToolResult:
|
|
subject: str = kwargs["subject"]
|
|
kv_api_url: str = kwargs.get("kv_api_url", _DEFAULT_KV_API_URL)
|
|
|
|
if not subject:
|
|
return ToolResult.fail("Subject identifier is required")
|
|
|
|
async with httpx.AsyncClient(
|
|
base_url=kv_api_url, timeout=_REQUEST_TIMEOUT
|
|
) as client:
|
|
try:
|
|
resp = await client.post(
|
|
f"/api/truth/subjects/{subject}/invalidate",
|
|
json={},
|
|
)
|
|
except httpx.ConnectError:
|
|
return ToolResult.fail(
|
|
f"Cannot connect to KV API at {kv_api_url}. "
|
|
"Start it with: cd codebase/tools/platform-knowledge-ai && ./run start"
|
|
)
|
|
except httpx.TimeoutException:
|
|
return ToolResult.fail(
|
|
f"Cache invalidation timed out after {_REQUEST_TIMEOUT}s"
|
|
)
|
|
|
|
if resp.status_code == 404:
|
|
return ToolResult.fail(
|
|
f"Subject '{subject}' not found. Available subjects are determined "
|
|
"by the content classification system."
|
|
)
|
|
|
|
if resp.status_code == 400:
|
|
error_data = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
|
|
error_msg = error_data.get("error", "Invalid request")
|
|
return ToolResult.fail(f"Bad request: {error_msg}")
|
|
|
|
if resp.status_code >= 500:
|
|
return ToolResult.fail(
|
|
f"KV API internal error (HTTP {resp.status_code}). "
|
|
"Check service logs for details."
|
|
)
|
|
|
|
if resp.status_code != 200:
|
|
return ToolResult.fail(
|
|
f"KV API returned unexpected status {resp.status_code}"
|
|
)
|
|
|
|
data = resp.json()
|
|
success = data.get("success", False)
|
|
|
|
if not success:
|
|
return ToolResult.fail(
|
|
f"Cache invalidation for subject '{subject}' failed. "
|
|
"Check KV API logs for details."
|
|
)
|
|
|
|
keys_invalidated = data.get("keysInvalidated", 0)
|
|
affected_locale_files = data.get("affectedLocaleFiles", [])
|
|
|
|
return ToolResult.success(
|
|
{
|
|
"subject": subject,
|
|
"keys_invalidated": keys_invalidated,
|
|
"affected_locale_files": affected_locale_files,
|
|
"success": True,
|
|
},
|
|
subject=subject,
|
|
keys_invalidated=keys_invalidated,
|
|
)
|