mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-11 15:13:23 +08:00
重构主控编排与运行时预热链路,统一工作区提示词/专家调度协议并补齐 wiki 记忆注入与写回闭环。
同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
This commit is contained in:
parent
4a23b715a2
commit
dbbe3add6a
14438 changed files with 2693620 additions and 2546 deletions
|
|
@ -0,0 +1,157 @@
|
|||
import Foundation
|
||||
|
||||
enum ToolResultTextFormatter {
|
||||
static func format(text: String, toolName: String?) -> String {
|
||||
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
guard !trimmed.isEmpty else { return "" }
|
||||
|
||||
guard self.looksLikeJSON(trimmed),
|
||||
let data = trimmed.data(using: .utf8),
|
||||
let json = try? JSONSerialization.jsonObject(with: data)
|
||||
else {
|
||||
return trimmed
|
||||
}
|
||||
|
||||
let normalizedTool = toolName?.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
||||
return self.renderJSON(json, toolName: normalizedTool)
|
||||
}
|
||||
|
||||
private static func looksLikeJSON(_ value: String) -> Bool {
|
||||
guard let first = value.first else { return false }
|
||||
return first == "{" || first == "["
|
||||
}
|
||||
|
||||
private static func renderJSON(_ json: Any, toolName: String?) -> String {
|
||||
if let dict = json as? [String: Any] {
|
||||
return self.renderDictionary(dict, toolName: toolName)
|
||||
}
|
||||
if let array = json as? [Any] {
|
||||
if array.isEmpty { return "No items." }
|
||||
return "\(array.count) item\(array.count == 1 ? "" : "s")."
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
private static func renderDictionary(_ dict: [String: Any], toolName: String?) -> String {
|
||||
let status = (dict["status"] as? String)?.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let errorText = self.firstString(in: dict, keys: ["error", "reason"])
|
||||
let messageText = self.firstString(in: dict, keys: ["message", "result", "detail"])
|
||||
|
||||
if status?.lowercased() == "error" || errorText != nil {
|
||||
if let errorText {
|
||||
return "Error: \(self.sanitizeError(errorText))"
|
||||
}
|
||||
if let messageText {
|
||||
return "Error: \(self.sanitizeError(messageText))"
|
||||
}
|
||||
return "Error"
|
||||
}
|
||||
|
||||
if toolName == "nodes", let summary = self.renderNodesSummary(dict) {
|
||||
return summary
|
||||
}
|
||||
|
||||
if let message = messageText {
|
||||
return message
|
||||
}
|
||||
|
||||
if let status, !status.isEmpty {
|
||||
return "Status: \(status)"
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
private static func renderNodesSummary(_ dict: [String: Any]) -> String? {
|
||||
if let nodes = dict["nodes"] as? [[String: Any]] {
|
||||
if nodes.isEmpty { return "No nodes found." }
|
||||
var lines: [String] = []
|
||||
lines.append("\(nodes.count) node\(nodes.count == 1 ? "" : "s") found.")
|
||||
|
||||
for node in nodes.prefix(3) {
|
||||
let label = self.firstString(in: node, keys: ["displayName", "name", "nodeId"]) ?? "Node"
|
||||
var details: [String] = []
|
||||
|
||||
if let connected = node["connected"] as? Bool {
|
||||
details.append(connected ? "connected" : "offline")
|
||||
}
|
||||
if let platform = self.firstString(in: node, keys: ["platform"]) {
|
||||
details.append(platform)
|
||||
}
|
||||
if let version = self.firstString(in: node, keys: ["osVersion", "appVersion", "version"]) {
|
||||
details.append(version)
|
||||
}
|
||||
if let pairing = self.pairingDetail(node) {
|
||||
details.append(pairing)
|
||||
}
|
||||
|
||||
if details.isEmpty {
|
||||
lines.append("• \(label)")
|
||||
} else {
|
||||
lines.append("• \(label) - \(details.joined(separator: ", "))")
|
||||
}
|
||||
}
|
||||
|
||||
let extra = nodes.count - 3
|
||||
if extra > 0 {
|
||||
lines.append("... +\(extra) more")
|
||||
}
|
||||
return lines.joined(separator: "\n")
|
||||
}
|
||||
|
||||
if let pending = dict["pending"] as? [Any], let paired = dict["paired"] as? [Any] {
|
||||
return "Pairing requests: \(pending.count) pending, \(paired.count) paired."
|
||||
}
|
||||
|
||||
if let pending = dict["pending"] as? [Any] {
|
||||
if pending.isEmpty { return "No pending pairing requests." }
|
||||
return "\(pending.count) pending pairing request\(pending.count == 1 ? "" : "s")."
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
private static func pairingDetail(_ node: [String: Any]) -> String? {
|
||||
if let paired = node["paired"] as? Bool, !paired {
|
||||
return "pairing required"
|
||||
}
|
||||
|
||||
for key in ["status", "state", "deviceStatus"] {
|
||||
if let raw = node[key] as? String, raw.lowercased().contains("pairing required") {
|
||||
return "pairing required"
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private static func firstString(in dict: [String: Any], keys: [String]) -> String? {
|
||||
for key in keys {
|
||||
if let value = dict[key] as? String {
|
||||
let trimmed = value.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if !trimmed.isEmpty {
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private static func sanitizeError(_ raw: String) -> String {
|
||||
var cleaned = raw.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
if cleaned.contains("agent="),
|
||||
cleaned.contains("action="),
|
||||
let marker = cleaned.range(of: ": ")
|
||||
{
|
||||
cleaned = String(cleaned[marker.upperBound...]).trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
}
|
||||
|
||||
if let firstLine = cleaned.split(separator: "\n").first {
|
||||
cleaned = String(firstLine).trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
}
|
||||
|
||||
if cleaned.count > 220 {
|
||||
cleaned = String(cleaned.prefix(217)) + "..."
|
||||
}
|
||||
return cleaned
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue