feat(#552): surface tool.output_risk WS event as security chip (#561)

Co-authored-by: M57 <m57@hermes-control.app>
This commit is contained in:
M57andM57 authored and GitHub committed 2026-07-12 13:21:07 +03:00
1 parent 3052db7d65
commit 168d27dcca
5 files changed
+156

No files matched your search

@@ -90,6 +90,18 @@ object EventParser {
WsEvent.ToolComplete(name, payload, sessionId)
}
"tool.output_risk" -> {
val toolId = payload?.get("tool_id") as? String ?: ""
val name = payload?.get("name") as? String ?: ""
val risk = (payload?.get("risk") as? String)?.lowercase() ?: "low"
val redacted = payload?.get("redacted") as? Boolean ?: false
@Suppress("UNCHECKED_CAST")
val findings = (payload?.get("findings") as? List<*>)?.filterIsInstance<String>() ?: emptyList()
WsEvent.ToolOutputRisk(toolId, name, risk, findings, redacted, sessionId)
}
"clarify.request" -> {
// Gateway sends "question"/"choices" — fall back to "text"/"options" for any
// older client or test that still uses the legacy field names. (Issue #206)
@@ -62,6 +62,23 @@ sealed class WsEvent {
val sessionId: String? = null,
) : WsEvent()
/**
* Backend flagged tool output as having potential risk (secrets, PII).
* Emitted alongside tool.progress — carries risk level, findings, and
* whether content was redacted.
*
* Events: `tool.output_risk`
* Payload: `{ tool_id, name, risk, findings[], redacted }`
*/
data class ToolOutputRisk(
val toolId: String = "",
val name: String = "",
val risk: String = "low",
val findings: List<String> = emptyList(),
val redacted: Boolean = false,
val sessionId: String? = null,
) : WsEvent()
// ── Interactive ──────────────────────────────────────────────────────
data class ClarifyRequest(