feat: Removed indicatif spinners. The UX just won't stop clobbering for parallel graph nodes
This commit is contained in:
Generated
+37
-69
@@ -183,13 +183,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "argc"
|
name = "argc"
|
||||||
version = "1.23.0"
|
version = "1.24.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ed45b16ecde78101a90574aeeac8e61749203b7dba72a4abb70a870e92af0047"
|
checksum = "17060e608fbc0809d62a996a65cdee9e7c441a979f40f2d1d2fbdce9eef60dad"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"base64",
|
"base64",
|
||||||
"convert_case 0.8.0",
|
"convert_case 0.11.0",
|
||||||
"dirs",
|
"dirs",
|
||||||
"either",
|
"either",
|
||||||
"indexmap 2.14.0",
|
"indexmap 2.14.0",
|
||||||
@@ -203,6 +203,7 @@ dependencies = [
|
|||||||
"shell-words",
|
"shell-words",
|
||||||
"textwrap",
|
"textwrap",
|
||||||
"threadpool",
|
"threadpool",
|
||||||
|
"unicode-width",
|
||||||
"which",
|
"which",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -271,9 +272,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.5.0"
|
version = "1.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aws-config"
|
name = "aws-config"
|
||||||
@@ -950,9 +951,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.20.2"
|
version = "3.20.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytemuck"
|
name = "bytemuck"
|
||||||
@@ -1264,19 +1265,6 @@ dependencies = [
|
|||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "console"
|
|
||||||
version = "0.15.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
|
|
||||||
dependencies = [
|
|
||||||
"encode_unicode",
|
|
||||||
"libc",
|
|
||||||
"once_cell",
|
|
||||||
"unicode-width",
|
|
||||||
"windows-sys 0.59.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "console"
|
name = "console"
|
||||||
version = "0.16.3"
|
version = "0.16.3"
|
||||||
@@ -1297,18 +1285,18 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.8.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baaaa0ecca5b51987b9423ccdc971514dd8b0bb7b4060b983d3664dad3f1f89f"
|
checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "convert_case"
|
name = "convert_case"
|
||||||
version = "0.10.0"
|
version = "0.11.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "633458d4ef8c78b72454de2d54fd6ab2e60f9e02be22f3c6104cdc8a4e0fceb9"
|
checksum = "affbf0190ed2caf063e3def54ff444b449371d55c58e513a95ab98eca50adb49"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
@@ -1671,7 +1659,7 @@ version = "0.12.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25f104b501bf2364e78d0d3974cbc774f738f5865306ed128e1e0d7499c0ad96"
|
checksum = "25f104b501bf2364e78d0d3974cbc774f738f5865306ed128e1e0d7499c0ad96"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console 0.16.3",
|
"console",
|
||||||
"shell-words",
|
"shell-words",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
@@ -1823,9 +1811,9 @@ checksum = "b2972feb8dffe7bc8c5463b1dacda1b0dfbed3710e50f977d965429692d74cd8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.15.0"
|
version = "1.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encode_unicode"
|
name = "encode_unicode"
|
||||||
@@ -2867,26 +2855,13 @@ dependencies = [
|
|||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "indicatif"
|
|
||||||
version = "0.17.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235"
|
|
||||||
dependencies = [
|
|
||||||
"console 0.15.11",
|
|
||||||
"number_prefix",
|
|
||||||
"portable-atomic",
|
|
||||||
"unicode-width",
|
|
||||||
"web-time",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indicatif"
|
name = "indicatif"
|
||||||
version = "0.18.4"
|
version = "0.18.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb"
|
checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"console 0.16.3",
|
"console",
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"unicode-width",
|
"unicode-width",
|
||||||
"unit-prefix",
|
"unit-prefix",
|
||||||
@@ -3085,9 +3060,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.98"
|
version = "0.3.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
|
checksum = "142bc4740e452c1e57ade0cbc129f139c9093e354346f0872ef985f4f5cf5f11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
@@ -3277,7 +3252,6 @@ dependencies = [
|
|||||||
"html_to_markdown",
|
"html_to_markdown",
|
||||||
"http 1.4.0",
|
"http 1.4.0",
|
||||||
"indexmap 2.14.0",
|
"indexmap 2.14.0",
|
||||||
"indicatif 0.17.11",
|
|
||||||
"indoc",
|
"indoc",
|
||||||
"inquire",
|
"inquire",
|
||||||
"is-terminal",
|
"is-terminal",
|
||||||
@@ -3605,12 +3579,6 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "number_prefix"
|
|
||||||
version = "0.4.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2"
|
name = "objc2"
|
||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
@@ -3993,9 +3961,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pastey"
|
name = "pastey"
|
||||||
version = "0.2.2"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c5a797f0e07bdf071d15742978fc3128ec6c22891c31a3a931513263904c982a"
|
checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "path-absolutize"
|
name = "path-absolutize"
|
||||||
@@ -4744,9 +4712,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roff"
|
name = "roff"
|
||||||
version = "0.2.2"
|
version = "1.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88f8660c1ff60292143c98d08fc6e2f654d722db50410e3f3797d40baaf9d8f3"
|
checksum = "323c417e1d9665a65b263ec744ba09030cfb277e9daa0b018a4ab62e57bc8189"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rpassword"
|
name = "rpassword"
|
||||||
@@ -5142,7 +5110,7 @@ dependencies = [
|
|||||||
"either",
|
"either",
|
||||||
"flate2",
|
"flate2",
|
||||||
"http 1.4.0",
|
"http 1.4.0",
|
||||||
"indicatif 0.18.4",
|
"indicatif",
|
||||||
"log",
|
"log",
|
||||||
"quick-xml 0.38.4",
|
"quick-xml 0.38.4",
|
||||||
"regex",
|
"regex",
|
||||||
@@ -5218,9 +5186,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.149"
|
version = "1.0.150"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.14.0",
|
"indexmap 2.14.0",
|
||||||
"itoa",
|
"itoa",
|
||||||
@@ -6545,9 +6513,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.121"
|
version = "0.2.122"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
|
checksum = "3ed04576f974d2b2fba0f38c51dbc5518011e38c36bf1143164be765528fd409"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -6558,9 +6526,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-futures"
|
name = "wasm-bindgen-futures"
|
||||||
version = "0.4.71"
|
version = "0.4.72"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8"
|
checksum = "9473dbd2991ae90b6291c3c32c30c6187ac49aa32f9905d1cce280ec1e110b0f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -6568,9 +6536,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.121"
|
version = "0.2.122"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
|
checksum = "916151b09da36bd82f6615cbf3a419e2f0ba23a03c6160e8e92eb6bd4aa1dec6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -6578,9 +6546,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.121"
|
version = "0.2.122"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
|
checksum = "299047362ccbfce148b67ab7e73349f77748e00c8296f9542adfad2ad82c5c5e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -6591,9 +6559,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.121"
|
version = "0.2.122"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
|
checksum = "9a929b2c61f11ba3e9bc35b50c1f25cb38e0e892c0c231ae2b8cf78d5dad4437"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
@@ -6730,9 +6698,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.98"
|
version = "0.3.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa"
|
checksum = "6d621441cfc37b84979402712047321980c178f299193a3589d05b99e8763436"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ unicode-width = "0.2.0"
|
|||||||
async-recursion = "1.1.1"
|
async-recursion = "1.1.1"
|
||||||
http = "1.1.0"
|
http = "1.1.0"
|
||||||
indexmap = { version = "2.2.6", features = ["serde"] }
|
indexmap = { version = "2.2.6", features = ["serde"] }
|
||||||
indicatif = "0.17"
|
|
||||||
hmac = "0.12.1"
|
hmac = "0.12.1"
|
||||||
aws-smithy-eventstream = "0.60.4"
|
aws-smithy-eventstream = "0.60.4"
|
||||||
urlencoding = "2.1.3"
|
urlencoding = "2.1.3"
|
||||||
|
|||||||
+54
-27
@@ -1,8 +1,7 @@
|
|||||||
use super::agent::AgentNodeExecutor;
|
use super::agent::AgentNodeExecutor;
|
||||||
use super::llm::{LlmExecutionOutcome, LlmNodeExecutor};
|
use super::llm::{LlmExecutionOutcome, LlmNodeExecutor};
|
||||||
use super::logging::{GraphLogger, node_type_label};
|
use super::logging::{GraphLogger, narrate_node_complete, narrate_node_failed};
|
||||||
use super::map::MapNodeExecutor;
|
use super::map::MapNodeExecutor;
|
||||||
use super::progress::{BranchProgressHandle, BranchProgressTracker};
|
|
||||||
use super::rag::RagNodeExecutor;
|
use super::rag::RagNodeExecutor;
|
||||||
use super::script::ScriptExecutor;
|
use super::script::ScriptExecutor;
|
||||||
use super::staging::BranchWrites;
|
use super::staging::BranchWrites;
|
||||||
@@ -152,14 +151,15 @@ impl GraphExecutor {
|
|||||||
let semaphore = Arc::new(Semaphore::new(max_concurrency));
|
let semaphore = Arc::new(Semaphore::new(max_concurrency));
|
||||||
|
|
||||||
let frontier_size = frontier.len();
|
let frontier_size = frontier.len();
|
||||||
let is_nested = ctx.current_depth > 0;
|
let in_super_step = frontier_size > 1;
|
||||||
let has_progress_nodes = frontier.iter().any(|nid| {
|
let silent = logger.silent();
|
||||||
graph.get_node(nid).is_some_and(|n| {
|
|
||||||
!matches!(n.node_type, NodeType::Approval(_) | NodeType::Input(_))
|
if in_super_step {
|
||||||
})
|
let mut branches = sorted_frontier(&frontier);
|
||||||
});
|
branches.sort();
|
||||||
let progress_tracker =
|
logger.super_step_start(&branches);
|
||||||
(has_progress_nodes && !is_nested).then(BranchProgressTracker::new);
|
}
|
||||||
|
|
||||||
let mut branch_tasks = Vec::with_capacity(frontier_size);
|
let mut branch_tasks = Vec::with_capacity(frontier_size);
|
||||||
for node_id in &frontier {
|
for node_id in &frontier {
|
||||||
let node = graph
|
let node = graph
|
||||||
@@ -168,34 +168,31 @@ impl GraphExecutor {
|
|||||||
anyhow!("Node '{}' not found in graph '{}'", node_id, graph.name)
|
anyhow!("Node '{}' not found in graph '{}'", node_id, graph.name)
|
||||||
})?
|
})?
|
||||||
.clone();
|
.clone();
|
||||||
|
logger.node_start(&node, in_super_step);
|
||||||
let branch_state = state.fork_for_branch_state();
|
let branch_state = state.fork_for_branch_state();
|
||||||
let mut branch_ctx = ctx.fork_for_branch();
|
let mut branch_ctx = ctx.fork_for_branch();
|
||||||
|
if in_super_step {
|
||||||
branch_ctx.render_mode = RenderMode::Silent;
|
branch_ctx.render_mode = RenderMode::Silent;
|
||||||
|
}
|
||||||
let script_exec_clone = script_executor.clone();
|
let script_exec_clone = script_executor.clone();
|
||||||
let graph_clone = Arc::clone(&graph);
|
let graph_clone = Arc::clone(&graph);
|
||||||
let current = node_id.clone();
|
let current = node_id.clone();
|
||||||
let sem_clone = semaphore.clone();
|
let sem_clone = semaphore.clone();
|
||||||
let abort_clone = abort_signal.clone();
|
let abort_clone = abort_signal.clone();
|
||||||
let progress_handle = match (
|
|
||||||
matches!(node.node_type, NodeType::Approval(_) | NodeType::Input(_)),
|
|
||||||
&progress_tracker,
|
|
||||||
) {
|
|
||||||
(false, Some(tracker)) => {
|
|
||||||
tracker.add_branch(&format!("{} ({})", node_id, node_type_label(&node)))
|
|
||||||
}
|
|
||||||
_ => BranchProgressHandle::disabled(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let task = tokio::spawn(async move {
|
let task = tokio::spawn(async move {
|
||||||
let mut progress_handle = Some(progress_handle);
|
|
||||||
let _permit = sem_clone
|
let _permit = sem_clone
|
||||||
.acquire()
|
.acquire()
|
||||||
.await
|
.await
|
||||||
.expect("semaphore should not be closed");
|
.expect("semaphore should not be closed");
|
||||||
if abort_clone.aborted() {
|
if abort_clone.aborted() {
|
||||||
if let Some(h) = progress_handle.take() {
|
narrate_node_failed(
|
||||||
h.fail("aborted");
|
silent,
|
||||||
}
|
&node,
|
||||||
|
Duration::default(),
|
||||||
|
"aborted",
|
||||||
|
in_super_step,
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
current.clone(),
|
current.clone(),
|
||||||
branch_state,
|
branch_state,
|
||||||
@@ -214,10 +211,38 @@ impl GraphExecutor {
|
|||||||
};
|
};
|
||||||
let result = step(&node, &mut state, &mut ctx, &step_ctx, ¤t).await;
|
let result = step(&node, &mut state, &mut ctx, &step_ctx, ¤t).await;
|
||||||
let elapsed = node_start.elapsed();
|
let elapsed = node_start.elapsed();
|
||||||
if let Some(h) = progress_handle.take() {
|
|
||||||
match &result {
|
match &result {
|
||||||
Ok(_) => h.complete(),
|
Ok(StepResult::Continue(targets)) => {
|
||||||
Err(e) => h.fail(&e.to_string()),
|
let route = if targets.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(targets.join(", "))
|
||||||
|
};
|
||||||
|
narrate_node_complete(
|
||||||
|
silent,
|
||||||
|
&node,
|
||||||
|
elapsed,
|
||||||
|
route.as_deref(),
|
||||||
|
in_super_step,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(StepResult::End(_)) => {
|
||||||
|
narrate_node_complete(
|
||||||
|
silent,
|
||||||
|
&node,
|
||||||
|
elapsed,
|
||||||
|
Some("END"),
|
||||||
|
in_super_step,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
narrate_node_failed(
|
||||||
|
silent,
|
||||||
|
&node,
|
||||||
|
elapsed,
|
||||||
|
&e.to_string(),
|
||||||
|
in_super_step,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(current, state, result, elapsed)
|
(current, state, result, elapsed)
|
||||||
@@ -226,7 +251,6 @@ impl GraphExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let joined = join_all(branch_tasks).await;
|
let joined = join_all(branch_tasks).await;
|
||||||
drop(progress_tracker);
|
|
||||||
|
|
||||||
let mut branch_writes: Vec<BranchWrites> = Vec::new();
|
let mut branch_writes: Vec<BranchWrites> = Vec::new();
|
||||||
let mut next_frontier: HashSet<String> = HashSet::new();
|
let mut next_frontier: HashSet<String> = HashSet::new();
|
||||||
@@ -294,6 +318,9 @@ impl GraphExecutor {
|
|||||||
return Ok(output);
|
return Ok(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if in_super_step {
|
||||||
|
logger.super_step_end(&sorted_frontier(&next_frontier));
|
||||||
|
}
|
||||||
frontier = next_frontier;
|
frontier = next_frontier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,24 @@
|
|||||||
use super::state::StateManager;
|
use super::state::StateManager;
|
||||||
use super::types::{Node, NodeType};
|
use super::types::{Node, NodeType};
|
||||||
use crate::utils::dimmed_text;
|
use crate::utils::dimmed_text;
|
||||||
|
use chrono::Local;
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use std::cmp::Reverse;
|
use std::cmp::Reverse;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
fn ts() -> String {
|
||||||
|
Local::now().format("%H:%M:%S").to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_secs(elapsed: Duration) -> String {
|
||||||
|
let secs = elapsed.as_secs_f64();
|
||||||
|
if secs < 1.0 {
|
||||||
|
format!("{}ms", elapsed.as_millis())
|
||||||
|
} else {
|
||||||
|
format!("{secs:.2}s")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
struct NodeTiming {
|
struct NodeTiming {
|
||||||
count: usize,
|
count: usize,
|
||||||
@@ -80,6 +94,43 @@ impl GraphLogger {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn silent(&self) -> bool {
|
||||||
|
self.silent
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn node_start(&self, node: &Node, in_super_step: bool) {
|
||||||
|
narrate_node_start(self.silent, node, in_super_step);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn super_step_start(&self, branches: &[String]) {
|
||||||
|
if self.silent {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
eprintln!(
|
||||||
|
"{}",
|
||||||
|
dimmed_text(&format!(
|
||||||
|
"▸ {} super-step start: {}",
|
||||||
|
ts(),
|
||||||
|
branches.join(", ")
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn super_step_end(&self, targets: &[String]) {
|
||||||
|
if self.silent {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let route = if targets.is_empty() {
|
||||||
|
String::new()
|
||||||
|
} else {
|
||||||
|
format!(" -> {}", targets.join(", "))
|
||||||
|
};
|
||||||
|
eprintln!(
|
||||||
|
"{}",
|
||||||
|
dimmed_text(&format!("▸ {} super-step end{route}", ts()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub fn record_timing(&mut self, node_id: &str, elapsed: Duration) {
|
pub fn record_timing(&mut self, node_id: &str, elapsed: Duration) {
|
||||||
self.timings
|
self.timings
|
||||||
.entry(node_id.to_string())
|
.entry(node_id.to_string())
|
||||||
@@ -144,6 +195,66 @@ impl GraphLogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn narrate_node_start(silent: bool, node: &Node, in_super_step: bool) {
|
||||||
|
if silent {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let indent = if in_super_step { " " } else { "" };
|
||||||
|
let label = node_type_label(node);
|
||||||
|
eprintln!(
|
||||||
|
"{}",
|
||||||
|
dimmed_text(&format!("▸ {} {indent}{} ({label}) start", ts(), node.id))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn narrate_node_complete(
|
||||||
|
silent: bool,
|
||||||
|
node: &Node,
|
||||||
|
elapsed: Duration,
|
||||||
|
next_target: Option<&str>,
|
||||||
|
in_super_step: bool,
|
||||||
|
) {
|
||||||
|
if silent {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let indent = if in_super_step { " " } else { "" };
|
||||||
|
let label = node_type_label(node);
|
||||||
|
let dur = fmt_secs(elapsed);
|
||||||
|
let route = next_target.map(|t| format!(" -> {t}")).unwrap_or_default();
|
||||||
|
eprintln!(
|
||||||
|
"{}",
|
||||||
|
dimmed_text(&format!(
|
||||||
|
"▸ {} {indent}{} ({label}) done in {dur}{route}",
|
||||||
|
ts(),
|
||||||
|
node.id
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn narrate_node_failed(
|
||||||
|
silent: bool,
|
||||||
|
node: &Node,
|
||||||
|
elapsed: Duration,
|
||||||
|
err: &str,
|
||||||
|
in_super_step: bool,
|
||||||
|
) {
|
||||||
|
if silent {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let indent = if in_super_step { " " } else { "" };
|
||||||
|
let label = node_type_label(node);
|
||||||
|
let dur = fmt_secs(elapsed);
|
||||||
|
let excerpt: String = err.chars().take(120).collect();
|
||||||
|
eprintln!(
|
||||||
|
"{}",
|
||||||
|
dimmed_text(&format!(
|
||||||
|
"▸ {} {indent}{} ({label}) FAILED in {dur} -- {excerpt}",
|
||||||
|
ts(),
|
||||||
|
node.id
|
||||||
|
))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) fn node_type_label(node: &Node) -> &'static str {
|
pub(super) fn node_type_label(node: &Node) -> &'static str {
|
||||||
match &node.node_type {
|
match &node.node_type {
|
||||||
NodeType::Agent(_) => "agent",
|
NodeType::Agent(_) => "agent",
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use super::agent::AgentNodeExecutor;
|
use super::agent::AgentNodeExecutor;
|
||||||
use super::executor::StepContext;
|
use super::executor::StepContext;
|
||||||
use super::llm::LlmNodeExecutor;
|
use super::llm::LlmNodeExecutor;
|
||||||
use super::progress::{BranchProgressHandle, BranchProgressTracker};
|
|
||||||
use super::rag::RagNodeExecutor;
|
use super::rag::RagNodeExecutor;
|
||||||
use super::state::StateManager;
|
use super::state::StateManager;
|
||||||
use super::types::{MapNode, NodeType};
|
use super::types::{MapNode, NodeType};
|
||||||
@@ -54,7 +53,6 @@ impl MapNodeExecutor {
|
|||||||
.unwrap_or(step_ctx.max_concurrency)
|
.unwrap_or(step_ctx.max_concurrency)
|
||||||
.max(1);
|
.max(1);
|
||||||
let semaphore = Arc::new(Semaphore::new(max_conc));
|
let semaphore = Arc::new(Semaphore::new(max_conc));
|
||||||
let progress_tracker = BranchProgressTracker::new();
|
|
||||||
let mut sub_tasks = Vec::with_capacity(items.len());
|
let mut sub_tasks = Vec::with_capacity(items.len());
|
||||||
|
|
||||||
for (idx, item) in items.iter().enumerate() {
|
for (idx, item) in items.iter().enumerate() {
|
||||||
@@ -68,21 +66,15 @@ impl MapNodeExecutor {
|
|||||||
let sub_branch_id = node.branch.clone();
|
let sub_branch_id = node.branch.clone();
|
||||||
let sem = semaphore.clone();
|
let sem = semaphore.clone();
|
||||||
let abort = step_ctx.abort_signal.clone();
|
let abort = step_ctx.abort_signal.clone();
|
||||||
let progress_handle: BranchProgressHandle =
|
|
||||||
progress_tracker.add_branch(&format!("{}[{idx}]", node.branch));
|
|
||||||
|
|
||||||
sub_state.state_mut().set(as_name, item);
|
sub_state.state_mut().set(as_name, item);
|
||||||
|
|
||||||
let task = tokio::spawn(async move {
|
let task = tokio::spawn(async move {
|
||||||
let mut progress_handle = Some(progress_handle);
|
|
||||||
let _permit = sem
|
let _permit = sem
|
||||||
.acquire()
|
.acquire()
|
||||||
.await
|
.await
|
||||||
.expect("map semaphore should not be closed");
|
.expect("map semaphore should not be closed");
|
||||||
if abort.aborted() {
|
if abort.aborted() {
|
||||||
if let Some(h) = progress_handle.take() {
|
|
||||||
h.fail("aborted");
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
idx,
|
idx,
|
||||||
sub_state,
|
sub_state,
|
||||||
@@ -110,20 +102,12 @@ impl MapNodeExecutor {
|
|||||||
)),
|
)),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(h) = progress_handle.take() {
|
|
||||||
match &exec_result {
|
|
||||||
Ok(_) => h.complete(),
|
|
||||||
Err(e) => h.fail(&e.to_string()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(idx, state, exec_result)
|
(idx, state, exec_result)
|
||||||
});
|
});
|
||||||
sub_tasks.push(task);
|
sub_tasks.push(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
let joined = join_all(sub_tasks).await;
|
let joined = join_all(sub_tasks).await;
|
||||||
drop(progress_tracker);
|
|
||||||
|
|
||||||
// Collect outputs keyed by input index so order is preserved regardless of finish order.
|
// Collect outputs keyed by input index so order is preserved regardless of finish order.
|
||||||
let mut outputs: HashMap<usize, Value> = HashMap::new();
|
let mut outputs: HashMap<usize, Value> = HashMap::new();
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ pub mod llm;
|
|||||||
pub mod logging;
|
pub mod logging;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod progress;
|
|
||||||
pub mod rag;
|
pub mod rag;
|
||||||
pub mod reducer;
|
pub mod reducer;
|
||||||
pub mod script;
|
pub mod script;
|
||||||
|
|||||||
@@ -1,71 +0,0 @@
|
|||||||
use crate::utils::IS_STDOUT_TERMINAL;
|
|
||||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
|
||||||
use std::sync::LazyLock;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
const GREEN: &str = "\x1b[32m";
|
|
||||||
const RED: &str = "\x1b[31m";
|
|
||||||
const RESET: &str = "\x1b[0m";
|
|
||||||
|
|
||||||
static SPINNER_STYLE: LazyLock<ProgressStyle> = LazyLock::new(|| {
|
|
||||||
ProgressStyle::with_template("{spinner} [{prefix}] {msg} ({elapsed})")
|
|
||||||
.expect("valid template")
|
|
||||||
.tick_strings(&["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏", ""])
|
|
||||||
});
|
|
||||||
|
|
||||||
pub(super) struct BranchProgressTracker {
|
|
||||||
multi: Option<MultiProgress>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BranchProgressTracker {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
if *IS_STDOUT_TERMINAL {
|
|
||||||
Self {
|
|
||||||
multi: Some(MultiProgress::new()),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Self { multi: None }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add_branch(&self, label: &str) -> BranchProgressHandle {
|
|
||||||
let Some(multi) = &self.multi else {
|
|
||||||
return BranchProgressHandle::disabled();
|
|
||||||
};
|
|
||||||
let bar = multi.add(ProgressBar::new_spinner());
|
|
||||||
bar.set_style(SPINNER_STYLE.clone());
|
|
||||||
bar.set_prefix(label.to_string());
|
|
||||||
bar.set_message("running…");
|
|
||||||
bar.enable_steady_tick(Duration::from_millis(80));
|
|
||||||
BranchProgressHandle { bar: Some(bar) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) struct BranchProgressHandle {
|
|
||||||
bar: Option<ProgressBar>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BranchProgressHandle {
|
|
||||||
pub fn disabled() -> Self {
|
|
||||||
Self { bar: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn complete(self) {
|
|
||||||
if let Some(bar) = self.bar {
|
|
||||||
bar.finish_with_message(format!("{GREEN}✓ done{RESET}"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn fail(self, err: &str) {
|
|
||||||
if let Some(bar) = self.bar {
|
|
||||||
let truncated = if err.len() > 80 {
|
|
||||||
let mut s = err[..80].to_string();
|
|
||||||
s.push('…');
|
|
||||||
s
|
|
||||||
} else {
|
|
||||||
err.to_string()
|
|
||||||
};
|
|
||||||
bar.finish_with_message(format!("{RED}✗ failed {RESET} — {truncated}"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user