Merge nucleic/zesty-jade-weasel-yb6i into dev
This commit is contained in:
@@ -41,6 +41,10 @@ enum SandboxToolDisplay {
|
|||||||
case "linux_container": "Linux container"
|
case "linux_container": "Linux container"
|
||||||
case "nucleic_supervise": "Supervising subagents"
|
case "nucleic_supervise": "Supervising subagents"
|
||||||
case AskUserQuestion.nucleicToolName: "Question for you"
|
case AskUserQuestion.nucleicToolName: "Question for you"
|
||||||
|
case "nucleic_knowledge_search": "Search project knowledge"
|
||||||
|
case "nucleic_knowledge_get": "Read project knowledge"
|
||||||
|
case "nucleic_knowledge_add": "Add project knowledge"
|
||||||
|
case "nucleic_knowledge_edit": "Edit project knowledge"
|
||||||
default: nil
|
default: nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,6 +75,10 @@ enum SandboxToolDisplay {
|
|||||||
case "linux_vm_control": "Managing the Linux VM…"
|
case "linux_vm_control": "Managing the Linux VM…"
|
||||||
case "nucleic_supervise": "Waiting on subagents…"
|
case "nucleic_supervise": "Waiting on subagents…"
|
||||||
case AskUserQuestion.nucleicToolName: "Waiting on your answer…"
|
case AskUserQuestion.nucleicToolName: "Waiting on your answer…"
|
||||||
|
case "nucleic_knowledge_search": "Searching project knowledge…"
|
||||||
|
case "nucleic_knowledge_get": "Reading project knowledge…"
|
||||||
|
case "nucleic_knowledge_add": "Adding to project knowledge…"
|
||||||
|
case "nucleic_knowledge_edit": "Editing project knowledge…"
|
||||||
default: nil
|
default: nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,6 +98,10 @@ enum SandboxToolDisplay {
|
|||||||
case "mac_vm_control", "linux_vm_control": "power"
|
case "mac_vm_control", "linux_vm_control": "power"
|
||||||
case "nucleic_supervise": "eye"
|
case "nucleic_supervise": "eye"
|
||||||
case AskUserQuestion.nucleicToolName: "questionmark.bubble"
|
case AskUserQuestion.nucleicToolName: "questionmark.bubble"
|
||||||
|
case "nucleic_knowledge_search": "magnifyingglass"
|
||||||
|
case "nucleic_knowledge_get": "point.3.connected.trianglepath.dotted"
|
||||||
|
case "nucleic_knowledge_add": "note.text.badge.plus"
|
||||||
|
case "nucleic_knowledge_edit": "square.and.pencil"
|
||||||
default: nil
|
default: nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,6 +141,16 @@ enum SandboxToolDisplay {
|
|||||||
let first = questions.first else { return nil }
|
let first = questions.first else { return nil }
|
||||||
let suffix = questions.count > 1 ? " +\(questions.count - 1) more" : ""
|
let suffix = questions.count > 1 ? " +\(questions.count - 1) more" : ""
|
||||||
return singleLine(first.question) + suffix
|
return singleLine(first.question) + suffix
|
||||||
|
// An empty query isn't a degenerate search — it's how the overview is asked for.
|
||||||
|
case "nucleic_knowledge_search":
|
||||||
|
return string(input, "query").map(singleLine) ?? "overview"
|
||||||
|
case "nucleic_knowledge_get":
|
||||||
|
return entityNames(input)
|
||||||
|
// Writes are shaped as arrays, so the row is what they add rather than one element of them.
|
||||||
|
case "nucleic_knowledge_add":
|
||||||
|
return addSummary(input)
|
||||||
|
case "nucleic_knowledge_edit":
|
||||||
|
return editSummary(input)
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -196,6 +218,46 @@ enum SandboxToolDisplay {
|
|||||||
return "\(op) — \(subject)"
|
return "\(op) — \(subject)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The entities a knowledge fetch asked for, joined — the names are the call. A lone `name` is
|
||||||
|
/// accepted too, since fetching one entity is the common case.
|
||||||
|
private static func entityNames(_ input: JSONValue) -> String? {
|
||||||
|
let names = (input["names"]?.arrayValue ?? [])
|
||||||
|
.compactMap { $0.stringValue ?? $0["name"]?.stringValue }
|
||||||
|
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
||||||
|
.filter { !$0.isEmpty }
|
||||||
|
guard !names.isEmpty else { return string(input, "name") }
|
||||||
|
return clip(names.joined(separator: ", "), limit: 60)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// What a knowledge write puts into the graph — "2 entities, 3 relations" — counted per bucket.
|
||||||
|
/// Observations carried inside an entity count toward the observation total, and so do anchors —
|
||||||
|
/// the schema only ever nests those, so the top-level bucket alone would always read as zero.
|
||||||
|
private static func addSummary(_ input: JSONValue) -> String? {
|
||||||
|
let entities = input["entities"]?.arrayValue ?? []
|
||||||
|
let nested = entities.reduce(0) { $0 + ($1["observations"]?.arrayValue?.count ?? 0) }
|
||||||
|
let nestedAnchors = entities.reduce(0) { $0 + ($1["anchors"]?.arrayValue?.count ?? 0) }
|
||||||
|
let buckets: [(singular: String, plural: String, count: Int)] = [
|
||||||
|
("entity", "entities", entities.count),
|
||||||
|
("observation", "observations",
|
||||||
|
(input["observations"]?.arrayValue?.count ?? 0) + nested),
|
||||||
|
("relation", "relations", input["relations"]?.arrayValue?.count ?? 0),
|
||||||
|
("anchor", "anchors",
|
||||||
|
(input["anchors"]?.arrayValue?.count ?? 0) + nestedAnchors),
|
||||||
|
]
|
||||||
|
let parts = buckets.filter { $0.count > 0 }
|
||||||
|
.map { "\($0.count) \($0.count == 1 ? $0.singular : $0.plural)" }
|
||||||
|
return parts.isEmpty ? nil : parts.joined(separator: ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A knowledge edit as how much it changes — "3 operations" — summed across its buckets, since
|
||||||
|
/// how many changes land says more in a one-line row than which bucket they came from.
|
||||||
|
private static func editSummary(_ input: JSONValue) -> String? {
|
||||||
|
let operations = (input.objectValue ?? [:]).values
|
||||||
|
.reduce(0) { $0 + ($1.arrayValue?.count ?? 0) }
|
||||||
|
guard operations > 0 else { return nil }
|
||||||
|
return "\(operations) operation\(operations == 1 ? "" : "s")"
|
||||||
|
}
|
||||||
|
|
||||||
/// A VM lifecycle op as a phrase, so "status" doesn't read as a state label.
|
/// A VM lifecycle op as a phrase, so "status" doesn't read as a state label.
|
||||||
private static func controlOpPhrase(_ op: String) -> String {
|
private static func controlOpPhrase(_ op: String) -> String {
|
||||||
switch op {
|
switch op {
|
||||||
|
|||||||
Reference in New Issue
Block a user