Merge nucleic/keen-feather-wren into dev
This commit is contained in:
+25
-25
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"originHash" : "997519e7bf6b3bb52f6f766bab10b0bf950c6beb140aa897dc50ba77eaaa5801",
|
"originHash" : "fa70224ebd92e3bfa55fbdf5bbea5d2a51a1f6402e805a443a323509fbc905ed",
|
||||||
"pins" : [
|
"pins" : [
|
||||||
{
|
{
|
||||||
"identity" : "async-http-client",
|
"identity" : "async-http-client",
|
||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/swift-server/async-http-client.git",
|
"location" : "https://github.com/swift-server/async-http-client.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "7744c2a035c68ec14726c709f031835e3e30bde1",
|
"revision" : "4603a8036d921ea999fadb742931546c341f4bd7",
|
||||||
"version" : "1.34.0"
|
"version" : "1.35.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -15,8 +15,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/groue/GRDB.swift.git",
|
"location" : "https://github.com/groue/GRDB.swift.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "9ed8c8457e00ff9c7aedb3bf213f20a2cfdf509e",
|
"revision" : "b83108d10f42680d78f23fe4d4d80fc88dab3212",
|
||||||
"version" : "7.11.0"
|
"version" : "7.11.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -24,8 +24,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/grpc/grpc-swift-2.git",
|
"location" : "https://github.com/grpc/grpc-swift-2.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "21fe69ab7ce0e87ac089534733c52f037e74a3eb",
|
"revision" : "28cdd63ef88583ddc67d7bb179eab46fab465ce9",
|
||||||
"version" : "2.4.1"
|
"version" : "2.4.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -33,8 +33,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/grpc/grpc-swift-nio-transport.git",
|
"location" : "https://github.com/grpc/grpc-swift-nio-transport.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "e7d463749f9037b047dcd6da4e633718ddc432b8",
|
"revision" : "2ca31f06658ed288a2560e23ad649acbb3d6b3a3",
|
||||||
"version" : "2.8.0"
|
"version" : "2.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -42,8 +42,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/grpc/grpc-swift-protobuf.git",
|
"location" : "https://github.com/grpc/grpc-swift-protobuf.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "b05885fa9bdd88f1eab2e7162f1ee81340b0da33",
|
"revision" : "176c5a434fd76f6f479848d1a8f7d44967534168",
|
||||||
"version" : "2.4.0"
|
"version" : "2.4.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -51,8 +51,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/sparkle-project/Sparkle",
|
"location" : "https://github.com/sparkle-project/Sparkle",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "d46d456107feacc80711b21847b82b07bd9fb46e",
|
"revision" : "b6496a74a087257ef5e6da1c5b29a447a60f5bd7",
|
||||||
"version" : "2.9.3"
|
"version" : "2.9.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -87,8 +87,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-async-algorithms.git",
|
"location" : "https://github.com/apple/swift-async-algorithms.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "d0b4a06d0f173a2f3be27d3ea21b3c3aa18db440",
|
"revision" : "3da39bbc4e687d4192af7c9cf4eab805745a0b9c",
|
||||||
"version" : "1.1.4"
|
"version" : "1.1.5"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -105,8 +105,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-certificates.git",
|
"location" : "https://github.com/apple/swift-certificates.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "bde8ca32a096825dfce37467137c903418c1893d",
|
"revision" : "89fbc3714264cce8db8e4ec51b64e01c3e28c6c5",
|
||||||
"version" : "1.19.1"
|
"version" : "1.19.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -168,8 +168,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-log.git",
|
"location" : "https://github.com/apple/swift-log.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "92448c359f00ebe36ae97d3bd9086f13c7692b5a",
|
"revision" : "a878e7f8f46cfc0e1125e565b5c08e7d5272dc9a",
|
||||||
"version" : "1.13.2"
|
"version" : "1.14.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -177,8 +177,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-nio.git",
|
"location" : "https://github.com/apple/swift-nio.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "77b84ac2cd2ac9e4ac67d19f045fd5b434f56967",
|
"revision" : "cd3e1152083706d77b223fb29110e590efcc70c0",
|
||||||
"version" : "2.101.0"
|
"version" : "2.101.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -186,8 +186,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-nio-extras.git",
|
"location" : "https://github.com/apple/swift-nio-extras.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "d2eeec0339074034f11a040a74aa2a341a2c4506",
|
"revision" : "88a51340f59cf181ebde888bd1b749296b3ec029",
|
||||||
"version" : "1.34.1"
|
"version" : "1.34.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -258,8 +258,8 @@
|
|||||||
"kind" : "remoteSourceControl",
|
"kind" : "remoteSourceControl",
|
||||||
"location" : "https://github.com/apple/swift-system.git",
|
"location" : "https://github.com/apple/swift-system.git",
|
||||||
"state" : {
|
"state" : {
|
||||||
"revision" : "7502b711c92a17741fa625d722b0ccbd595d8ed1",
|
"revision" : "b5544ba79a70a0cb3563e75bf26dc198d6b40ed3",
|
||||||
"version" : "1.7.2"
|
"version" : "1.7.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -204,7 +204,10 @@ enum SubagentRunState {
|
|||||||
|
|
||||||
init(group: ToolGroup) {
|
init(group: ToolGroup) {
|
||||||
if !group.finished { self = .running }
|
if !group.finished { self = .running }
|
||||||
else if group.isError { self = .failed }
|
// A `Task` subagent surfaces failure as an error result. A `nucleic_subagent` worker
|
||||||
|
// instead returns a *non-error* result whose JSON envelope carries `{"ok": false}` (or
|
||||||
|
// `{"denied": true}`) in-band, so read that too — otherwise a failed worker reads "Done".
|
||||||
|
else if group.isError || Subagent.workerFailed(group) { self = .failed }
|
||||||
else { self = .done }
|
else { self = .done }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,9 +237,14 @@ enum Subagent {
|
|||||||
return (raw?.isEmpty == false) ? raw : nil
|
return (raw?.isEmpty == false) ? raw : nil
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The one-line task the parent handed the subagent (`description`), falling back to the
|
/// The one-line task the parent handed the subagent: a `nucleic_subagent` worker's `task`
|
||||||
/// full `prompt`, then a generic label.
|
/// label, or a `Task` subagent's `description`, falling back to the full `prompt`, then a
|
||||||
|
/// generic label.
|
||||||
static func taskLabel(_ group: ToolGroup) -> String {
|
static func taskLabel(_ group: ToolGroup) -> String {
|
||||||
|
if let task = group.input["task"]?.stringValue?
|
||||||
|
.trimmingCharacters(in: .whitespacesAndNewlines), !task.isEmpty {
|
||||||
|
return task
|
||||||
|
}
|
||||||
if let description = group.input["description"]?.stringValue?
|
if let description = group.input["description"]?.stringValue?
|
||||||
.trimmingCharacters(in: .whitespacesAndNewlines), !description.isEmpty {
|
.trimmingCharacters(in: .whitespacesAndNewlines), !description.isEmpty {
|
||||||
return description
|
return description
|
||||||
@@ -258,9 +266,48 @@ enum Subagent {
|
|||||||
/// The subagent's returned report, or nil while it's still working / reported nothing.
|
/// The subagent's returned report, or nil while it's still working / reported nothing.
|
||||||
static func report(_ group: ToolGroup) -> String? {
|
static func report(_ group: ToolGroup) -> String? {
|
||||||
guard let result = group.result else { return nil }
|
guard let result = group.result else { return nil }
|
||||||
|
// A `nucleic_subagent` worker returns a JSON envelope — surface its actual `output` (or
|
||||||
|
// failure `message`) rather than a one-line gist of the raw `{ok,session_id,…}` object. A
|
||||||
|
// `Task` subagent returns prose, which falls through to the gist unchanged.
|
||||||
|
if let worker = workerText(result.resultText), !worker.isEmpty { return worker }
|
||||||
let text = result.compactSummary
|
let text = result.compactSummary
|
||||||
return text.isEmpty ? nil : text
|
return text.isEmpty ? nil : text
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether a `nucleic_subagent` worker result reports failure — a `{"ok": false}` completion
|
||||||
|
/// or a `{"denied": true}` refusal, both delivered as non-error tool results. False for any
|
||||||
|
/// other tool (a `Task` subagent, whose failure is an error result handled separately).
|
||||||
|
static func workerFailed(_ group: ToolGroup) -> Bool {
|
||||||
|
guard let result = group.result,
|
||||||
|
let envelope = workerEnvelope(result.resultText) else { return false }
|
||||||
|
if let denied = envelope["denied"] as? Bool, denied { return true }
|
||||||
|
if let ok = envelope["ok"] as? Bool { return !ok }
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The human-facing text of a `nucleic_subagent` worker envelope — the worker's `output` on
|
||||||
|
/// success, or its `message` on failure/denial — or nil when `text` isn't such an envelope
|
||||||
|
/// (so a `Task` subagent's prose report falls through unchanged).
|
||||||
|
private static func workerText(_ text: String) -> String? {
|
||||||
|
guard let envelope = workerEnvelope(text) else { return nil }
|
||||||
|
if let denied = envelope["denied"] as? Bool, denied {
|
||||||
|
return envelope["message"] as? String ?? ""
|
||||||
|
}
|
||||||
|
guard let ok = envelope["ok"] as? Bool else { return nil }
|
||||||
|
return ok ? (envelope["output"] as? String ?? "")
|
||||||
|
: (envelope["message"] as? String ?? "")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a `nucleic_subagent` result string into its JSON envelope, gated on the envelope's
|
||||||
|
/// signature keys (`ok` / `denied`) so an arbitrary JSON-shaped tool result isn't mistaken for
|
||||||
|
/// one. Nil for anything that isn't a worker envelope.
|
||||||
|
private static func workerEnvelope(_ text: String) -> [String: Any]? {
|
||||||
|
guard let data = text.data(using: .utf8),
|
||||||
|
let object = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
||||||
|
object["ok"] != nil || object["denied"] != nil
|
||||||
|
else { return nil }
|
||||||
|
return object
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A small leading status glyph for a subagent — a gold spinner while it works, a green check or
|
/// A small leading status glyph for a subagent — a gold spinner while it works, a green check or
|
||||||
@@ -531,7 +578,7 @@ enum ToolGlyph {
|
|||||||
case "Edit", "Write", "MultiEdit", "NotebookEdit": return "pencil"
|
case "Edit", "Write", "MultiEdit", "NotebookEdit": return "pencil"
|
||||||
case "Grep", "Glob", "Search": return "magnifyingglass"
|
case "Grep", "Glob", "Search": return "magnifyingglass"
|
||||||
case "WebFetch", "WebSearch": return "globe"
|
case "WebFetch", "WebSearch": return "globe"
|
||||||
case "Task", "Agent": return "person.2"
|
case "Task", "Agent", ToolGroup.orchestraSubagentToolName: return "person.2"
|
||||||
case "TodoWrite": return "checklist"
|
case "TodoWrite": return "checklist"
|
||||||
case "AskUserQuestion": return "questionmark.bubble"
|
case "AskUserQuestion": return "questionmark.bubble"
|
||||||
case HostCommandSummary.hostExecToolName: return "desktopcomputer"
|
case HostCommandSummary.hostExecToolName: return "desktopcomputer"
|
||||||
|
|||||||
@@ -76,8 +76,16 @@ struct ToolGroup: Equatable {
|
|||||||
|
|
||||||
struct FilePatch: Equatable { let path: String; let change: FileChange.ChangeKind }
|
struct FilePatch: Equatable { let path: String; let change: FileChange.ChangeKind }
|
||||||
|
|
||||||
/// Subagent orchestration (`Task`/`Agent`) gets the gold card treatment, like the Mac.
|
/// Nucleic's own Orchestra worker spawn — the qualified `nucleic_subagent` MCP wire name.
|
||||||
var isOrchestration: Bool { name == "Task" || name == "Agent" }
|
/// Unlike a `Task` subagent, a worker runs as its own observed session, so it carries no
|
||||||
|
/// nested `children` here; its card shows the final output it returned instead.
|
||||||
|
static let orchestraSubagentToolName = "mcp__nucleic__nucleic_subagent"
|
||||||
|
|
||||||
|
/// Subagent orchestration — a `Task`/`Agent` spawn or a `nucleic_subagent` worker — gets the
|
||||||
|
/// gold card treatment, like the Mac.
|
||||||
|
var isOrchestration: Bool {
|
||||||
|
name == "Task" || name == "Agent" || name == Self.orchestraSubagentToolName
|
||||||
|
}
|
||||||
var isAskUserQuestion: Bool { name == "AskUserQuestion" }
|
var isAskUserQuestion: Bool { name == "AskUserQuestion" }
|
||||||
|
|
||||||
/// The literal shell command a `Bash` call ran, if any (nil for every other tool). Used to
|
/// The literal shell command a `Bash` call ran, if any (nil for every other tool). Used to
|
||||||
|
|||||||
Reference in New Issue
Block a user