Self-hosted, Docker-based agentic troubleshooting platform: FastAPI backend + LangGraph agent, Next.js UI, tiered LLM routing (local Ollama -> Gemini -> DeepSeek -> OpenRouter), MCP server manager, encrypted device credentials, RBAC, audit log, project-memory + Obsidian integrations, and editable troubleshooting decision rules tuned for the GeneseasX vessel stack. Co-authored-by: Cursor <cursoragent@cursor.com>
61 lines
1.4 KiB
Python
61 lines
1.4 KiB
Python
"""Build safe payloads for tool_call / tool_start events."""
|
|
from __future__ import annotations
|
|
|
|
from app.services.diagnostic_format import MAX_EVENT_OUTPUT
|
|
|
|
_SECRET_KEYS = frozenset(
|
|
{
|
|
"password",
|
|
"secret",
|
|
"api_key",
|
|
"token_secret",
|
|
"token",
|
|
"private_key",
|
|
}
|
|
)
|
|
|
|
|
|
def sanitize_tool_args(args: dict | None) -> dict:
|
|
if not args:
|
|
return {}
|
|
out: dict = {}
|
|
for key, val in args.items():
|
|
if key.lower() in _SECRET_KEYS:
|
|
out[key] = "••••"
|
|
elif isinstance(val, str) and len(val) > 500:
|
|
out[key] = val[:500] + "…"
|
|
else:
|
|
out[key] = val
|
|
return out
|
|
|
|
|
|
def tool_event_payload(
|
|
*,
|
|
device: str,
|
|
tool: str,
|
|
args: dict | None = None,
|
|
status: str = "done",
|
|
ok: bool | None = None,
|
|
output: str | None = None,
|
|
error: str | None = None,
|
|
**extra,
|
|
) -> dict:
|
|
safe = sanitize_tool_args(args)
|
|
payload: dict = {
|
|
"device": device,
|
|
"tool": tool,
|
|
"status": status,
|
|
**extra,
|
|
}
|
|
if safe:
|
|
payload["args"] = safe
|
|
if safe.get("command"):
|
|
payload["command"] = safe["command"]
|
|
if ok is not None:
|
|
payload["ok"] = ok
|
|
if output is not None:
|
|
payload["output"] = output[:MAX_EVENT_OUTPUT]
|
|
if error is not None:
|
|
payload["error"] = error
|
|
return payload
|