

























1+package ai.openclaw.app
2+3+import ai.openclaw.app.node.asObjectOrNull
4+import ai.openclaw.app.node.asStringOrNull
5+import kotlinx.serialization.json.Json
6+import kotlinx.serialization.json.JsonArray
7+import kotlinx.serialization.json.JsonElement
8+import kotlinx.serialization.json.JsonObject
9+import kotlinx.serialization.json.JsonPrimitive
10+11+data class GatewayExecApprovalSummary(
12+val id: String,
13+val commandText: String,
14+val commandPreview: String?,
15+val allowedDecisions: List<String>,
16+val host: String?,
17+val nodeId: String?,
18+val agentId: String?,
19+val createdAtMs: Long?,
20+val expiresAtMs: Long?,
21+val resolvingDecision: String? = null,
22+val errorText: String? = null,
23+)
24+25+internal fun parseGatewayExecApprovalListPayload(
26+payloadJson: String,
27+json: Json,
28+): List<GatewayExecApprovalSummary> =
29+try {
30+ (json.parseToJsonElement(payloadJson) as? JsonArray)
31+ ?.mapNotNull(::parseGatewayExecApprovalListEntry)
32+ ?.sortedBy { it.createdAtMs ?: Long.MAX_VALUE }
33+ .orEmpty()
34+ } catch (_: Throwable) {
35+ emptyList()
36+ }
37+38+internal fun parseGatewayExecApprovalListEntry(item: JsonElement): GatewayExecApprovalSummary? {
39+val obj = item.asObjectOrNull() ?: return null
40+val id = obj["id"].asStringOrNull()?.trim().orEmpty()
41+if (id.isEmpty()) return null
42+val request = obj["request"].asObjectOrNull()
43+val commandText = gatewayExecApprovalListCommandText(obj, request)
44+return GatewayExecApprovalSummary(
45+ id = id,
46+ commandText = commandText,
47+ commandPreview = gatewayExecApprovalListCommandPreview(obj, request, commandText),
48+ allowedDecisions = emptyList(),
49+ host =
50+ request
51+ ?.get("host")
52+ .asStringOrNull()
53+ ?.trim()
54+ ?.takeIf { it.isNotEmpty() },
55+ nodeId =
56+ request
57+ ?.get("nodeId")
58+ .asStringOrNull()
59+ ?.trim()
60+ ?.takeIf { it.isNotEmpty() },
61+ agentId =
62+ request
63+ ?.get("agentId")
64+ .asStringOrNull()
65+ ?.trim()
66+ ?.takeIf { it.isNotEmpty() },
67+ createdAtMs = obj.long("createdAtMs"),
68+ expiresAtMs = obj.long("expiresAtMs"),
69+ )
70+}
71+72+internal fun parseGatewayExecApprovalDetail(
73+obj: JsonObject,
74+createdAtMs: Long?,
75+): GatewayExecApprovalSummary? {
76+val id = obj["id"].asStringOrNull()?.trim().orEmpty()
77+if (id.isEmpty()) return null
78+return GatewayExecApprovalSummary(
79+ id = id,
80+ commandText =
81+ obj["commandText"]
82+ .asStringOrNull()
83+ ?.trim()
84+ ?.takeIf { it.isNotEmpty() }
85+?: "Command request",
86+ commandPreview =
87+ obj["commandPreview"]
88+ .asStringOrNull()
89+ ?.trim()
90+ ?.takeIf { it.isNotEmpty() },
91+ allowedDecisions = gatewayExecApprovalAllowedDecisions(obj),
92+ host = obj["host"].asStringOrNull()?.trim()?.takeIf { it.isNotEmpty() },
93+ nodeId = obj["nodeId"].asStringOrNull()?.trim()?.takeIf { it.isNotEmpty() },
94+ agentId = obj["agentId"].asStringOrNull()?.trim()?.takeIf { it.isNotEmpty() },
95+ createdAtMs = createdAtMs,
96+ expiresAtMs = obj.long("expiresAtMs"),
97+ )
98+}
99+100+private fun gatewayExecApprovalListCommandText(obj: JsonObject, request: JsonObject?): String =
101+ obj["commandText"]
102+ .asStringOrNull()
103+ ?.trim()
104+ ?.takeIf { it.isNotEmpty() }
105+?: request
106+ ?.get("command")
107+ .asStringOrNull()
108+ ?.trim()
109+ ?.takeIf { it.isNotEmpty() }
110+?: "Command request"
111+112+private fun gatewayExecApprovalListCommandPreview(
113+obj: JsonObject,
114+request: JsonObject?,
115+commandText: String,
116+): String? {
117+val preview =
118+ obj["commandPreview"]
119+ .asStringOrNull()
120+ ?.trim()
121+ ?.takeIf { it.isNotEmpty() }
122+?: request
123+ ?.get("commandPreview")
124+ .asStringOrNull()
125+ ?.trim()
126+ ?.takeIf { it.isNotEmpty() }
127+return preview?.takeIf { it != commandText }
128+}
129+130+private fun gatewayExecApprovalAllowedDecisions(request: JsonObject?): List<String> {
131+val explicit = parseGatewayExecApprovalDecisions(request?.get("allowedDecisions") as? JsonArray)
132+if (explicit.isNotEmpty()) return explicit
133+val allowed =
134+if (request
135+ ?.get("ask")
136+ .asStringOrNull()
137+ ?.trim()
138+ ?.lowercase() == "always"
139+ ) {
140+listOf("allow-once", "deny")
141+ } else {
142+listOf("allow-once", "allow-always", "deny")
143+ }
144+val unavailable = parseGatewayExecApprovalDecisions(request?.get("unavailableDecisions") as? JsonArray).toSet()
145+return allowed.filterNot { it == "allow-always" && it in unavailable }
146+}
147+148+private fun parseGatewayExecApprovalDecisions(items: JsonArray?): List<String> =
149+ items
150+ ?.mapNotNull { item ->
151+when (item.asStringOrNull()?.trim()) {
152+"allow-once" -> "allow-once"
153+"allow-always" -> "allow-always"
154+"deny" -> "deny"
155+else -> null
156+ }
157+ }?.distinct()
158+ .orEmpty()
159+160+private fun JsonObject?.long(key: String): Long? = (this?.get(key) as? JsonPrimitive)?.content?.trim()?.toLongOrNull()
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。