### Integrate C++ Agentic Framework with CMake Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Demonstrates how to integrate the C++ Agentic Framework into an existing CMake project. It shows how to find the installed framework and link it to a target, ensuring C++20 compatibility. ```cmake # Find the framework find_package(AgenticFramework REQUIRED) # Link to your target target_link_libraries(your_target PRIVATE AgenticFramework::Core ) # Enable C++20 target_compile_features(your_target PRIVATE cxx_std_20) ``` -------------------------------- ### Performance Optimization in C++ Agentic Framework Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Illustrates performance optimization techniques in a Node. It highlights reserving container capacity to avoid reallocations and utilizing move semantics for efficient data transfer. ```cpp class OptimizedNode : public Node { public: std::shared_ptr Exec(std::shared_ptr prep_res) override { // ✅ Good: Reserve container capacity std::vector results; results.reserve(expected_size); // ✅ Good: Use move semantics return std::make_shared(std::move(processed_string)); } private: static constexpr size_t expected_size = 1000; }; ``` -------------------------------- ### Build C++ Agentic Framework using Bash Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Instructions for cloning the C++ Agentic Framework repository, configuring the build with CMake, and compiling the project using parallel builds. It also includes an optional step for running tests. ```bash # Clone the repository git clone cd agentic-framework # Create build directory mkdir build && cd build # Configure with CMake cmake .. -DCMAKE_BUILD_TYPE=Release # Build cmake --build . --parallel # Run tests (optional) ctest --parallel ``` -------------------------------- ### Sequential Processing Chain in C++ Flow Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Illustrates building a sequential processing chain using multiple nodes (ValidationNode, TextProcessorNode, LoggingNode) in C++. It shows how to link nodes using the `next()` method and execute data through the entire flow. ```cpp #include "Flow/Flow.h" // Create multiple processing nodes auto validator = std::make_shared(); auto transformer = std::make_shared(); auto logger = std::make_shared(); // Chain them together validator->next(transformer); transformer->next(logger); // Create a flow auto flow = std::make_shared(validator); // Process data through the entire chain auto input = std::make_shared("input data"); auto result = flow->orch(input); ``` -------------------------------- ### Use Custom TextProcessorNode in C++ Application Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Demonstrates how to instantiate and utilize the 'TextProcessorNode' within a C++ main function. It shows setting parameters, providing input, executing the node, and handling the output, including error management. ```cpp #include "TextProcessorNode.h" int main() { try { // Create the node auto processor = std::make_shared(); // Configure the operation std::map> params; params["operation"] = std::make_shared("uppercase"); processor->setParam(std::move(params)); // Create input data auto input = std::make_shared("hello world"); // Process the data auto result = processor->Execute(input); // Extract the result if (auto* output = result->as()) { std::cout << "Result: " << output->value << std::endl; // "HELLO WORLD" } } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; } return 0; } ``` -------------------------------- ### Async Data Fetching with Timeout and Cancellation (C++) Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Demonstrates how to perform asynchronous data fetching using `AsyncNode` and handle potential timeouts or cancellations. It simulates network requests and shows how to manage futures with `RunAsyncWithTimeout` and `RunAsyncWithCancellation`. Dependencies include `AsyncNode.h` and `CancellationToken.h`. ```cpp #include "AsyncNode/AsyncNode.h" #include "BaseNode/CancellationToken.h" class AsyncDataFetcher : public AsyncNode { public: std::future> ExecAsync( std::shared_ptr prep_res) override { return std::async(std::launch::async, [prep_res]() { // Simulate network request or file I/O std::this_thread::sleep_for(std::chrono::seconds(2)); if (auto* url = prep_res->as()) { // Simulate fetched data auto result = std::make_shared( "Data from: " + url->value ); return std::static_pointer_cast(result); } throw std::invalid_argument("Expected URL string"); }); } }; // Usage with timeout and cancellation int main() { auto fetcher = std::make_shared(); auto url = std::make_shared("https://api.example.com/data"); try { // With timeout auto future = fetcher->RunAsyncWithTimeout( url, std::chrono::seconds(5) ); auto result = future.get(); std::cout << "Fetch completed" << std::endl; } catch (const std::runtime_error& e) { std::cerr << "Fetch timed out: " << e.what() << std::endl; } // With cancellation CancellationToken token; auto cancel_future = fetcher->RunAsyncWithCancellation(url, token); // Cancel after 1 second std::this_thread::sleep_for(std::chrono::seconds(1)); token.cancel(); try { auto result = cancel_future.get(); } catch (const std::runtime_error& e) { std::cout << "Operation cancelled" << std::endl; } return 0; } ``` -------------------------------- ### Conditional Branching in C++ Node Logic Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Demonstrates implementing conditional branching within a C++ node's logic. The example shows a 'ValidationNode' that routes execution to different successor nodes ('SuccessNode' or 'ErrorHandlerNode') based on the processing result, eventually converging at a 'FinalNode'. ```cpp // Create nodes for different paths auto validator = std::make_shared(); auto success_processor = std::make_shared(); auto error_handler = std::make_shared(); auto final_node = std::make_shared(); // Set up conditional routing validator->next(success_processor, "valid"); validator->next(error_handler, "invalid"); // Both paths converge at the final node success_processor->next(final_node); error_handler->next(final_node); // The validator node determines the path based on its logic class ValidationNode : public Node { public: std::shared_ptr Post( std::shared_ptr shared, std::shared_ptr prep_res, std::shared_ptr exec_res) override { // Determine next action based on validation result if (auto* result = exec_res->as()) { if (result->value == "valid") { // Flow will automatically route to "valid" successor return exec_res; } } // Default routing or error case return exec_res; } }; ``` -------------------------------- ### Resource Cleanup in C++ Agentic Framework Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Demonstrates how to manage expensive resources within an AsyncNode using std::unique_ptr for automatic cleanup. The cleanup_resources method is overridden to ensure the resource is properly released. ```cpp class ResourceManagedNode : public AsyncNode { private: std::unique_ptr resource_; public: ResourceManagedNode() : resource_(std::make_unique()) {} std::future> ExecAsync( std::shared_ptr prep_res) override { // Capture resource in lambda for safe async access auto resource_ptr = resource_.get(); return std::async(std::launch::async, [prep_res, resource_ptr]() { // Use resource safely return resource_ptr->process(prep_res); }); } private: void cleanup_resources() noexcept override { // Custom cleanup if needed resource_.reset(); } }; ``` -------------------------------- ### Async Batch Processing with AsyncBatchNode in C++ Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Implements asynchronous batch processing using the AsyncBatchNode. The exec method handles a VectorData object, simulating an asynchronous operation with a delay, and returns processed items in a new VectorData. Dependencies include AsyncBatchNode.h and FrameworkData. ```cpp #include "AsyncBatchNode/AsyncBatchNode.h" class AsyncBatchProcessor : public AsyncBatchNode { private: std::shared_ptr exec(std::shared_ptr items) override { auto* batch = items->as(); if (!batch) { throw std::invalid_argument("Expected VectorData for async batch processing"); } // Simulate async batch processing std::this_thread::sleep_for(std::chrono::milliseconds(100)); auto result = std::make_shared(); result->data.reserve(batch->data.size()); for (const auto& item : batch->data) { if (auto* str_item = item->as()) { result->data.push_back( std::make_shared("AsyncBatch: " + str_item->value) ); } } return result; } }; // Usage auto async_batch_processor = std::make_shared(); auto batch = std::make_shared(); // ... populate batch ... // Process asynchronously auto future = async_batch_processor->RunAsync(batch); auto result = future.get(); // Non-blocking batch processing ``` -------------------------------- ### Parameter Validation Best Practice (C++) Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Shows how to implement robust parameter validation within a `ValidatingNode`. The `Prep` and `validateParams` methods demonstrate early checks for required parameters and valid data types/ranges, throwing `FrameworkError` exceptions for invalid configurations. This ensures the node operates with correct inputs. ```cpp class ValidatingNode : public Node { public: std::shared_ptr Prep(std::shared_ptr shared) override { // ✅ Good: Validate parameters early validateParams(); auto required_param = getParamSafe("required_config"); if (!required_param) { throw FrameworkError::invalid_argument( "Missing required parameter: required_config", "ValidatingNode::Prep" ); } return shared; } void validateParams() const override { // Implement parameter validation logic auto timeout = getParam("timeout"); if (timeout) { if (auto* timeout_data = timeout->as>()) { if (timeout_data->get() <= 0) { throw FrameworkError::invalid_argument( "Timeout must be positive", "ValidatingNode::validateParams" ); } } } } }; ``` -------------------------------- ### C++ Advanced Flow Management with AsyncFlow Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Illustrates different asynchronous flow management types: AsyncFlow for general non-blocking workflows, AsyncBatchFlow for batch processing, and AsyncParallelBatchFlow for maximum performance. These flows support timeouts and cancellation for robust execution. ```cpp #include "AsyncFlow/AsyncFlow.h" #include "AsyncBatchFlow/AsyncBatchFlow.h" #include "AsyncParallelBatchFlow/AsyncParallelBatchFlow.h" #include #include // Assuming start_node, batch_start_node, parallel_start_node, input, batch_input, large_batch_input are defined elsewhere // AsyncFlow - Non-blocking workflow execution // auto async_flow = std::make_shared(start_node); // auto future = async_flow->RunAsync(input); // AsyncBatchFlow - Non-blocking batch workflow // auto async_batch_flow = std::make_shared(batch_start_node); // auto batch_future = async_batch_flow->RunAsync(batch_input); // AsyncParallelBatchFlow - Maximum performance workflow // auto parallel_flow = std::make_shared(parallel_start_node); // auto parallel_future = parallel_flow->RunAsync(large_batch_input); // All can be used with timeouts and cancellation // try { // auto result = parallel_flow->RunAsyncWithTimeout( // large_batch_input, // std::chrono::minutes(5) // ).get(); // } catch (const std::runtime_error& e) { // std::cout << "Processing timed out" << std::endl; // } ``` -------------------------------- ### GitHub Actions CI Workflow for C++ Agentic Framework Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/BUILD.md An example GitHub Actions workflow file that automates the CI process for the C++ agentic framework. It checks out the code, installs dependencies, and runs the CI pipeline script on push and pull request events. ```yaml name: CI on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install dependencies run: | sudo apt update sudo apt install cmake ninja-build clang-tidy cppcheck - name: Run CI pipeline run: ./build.sh ci ``` -------------------------------- ### C++ Parallel Batch Processing with Futures Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Demonstrates parallel batch processing using std::async and std::future. This pattern is suitable for high-throughput scenarios where individual items in a batch can be processed independently. It involves launching asynchronous tasks for each item and collecting their results. ```cpp #include "AsyncParallelBatchNode/AsyncParallelBatchNode.h" #include #include #include #include #include class ParallelBatchProcessor : public AsyncParallelBatchNode { private: std::shared_ptr exec(std::shared_ptr items) override { auto* batch = items->as(); if (!batch) { throw std::invalid_argument("Expected VectorData for parallel batch processing"); } std::vector>> futures; futures.reserve(batch->data.size()); for (const auto& item : batch->data) { futures.emplace_back( std::async(std::launch::async, [item]() -> std::shared_ptr { if (auto* str_item = item->as()) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); return std::make_shared("Parallel: " + str_item->value); } return item; }) ); } auto result = std::make_shared(); result->data.reserve(futures.size()); for (auto& future : futures) { result->data.push_back(future.get()); } return result; } }; // Usage for high-throughput scenarios // auto parallel_processor = std::make_shared(); // auto large_batch = std::make_shared(); // Create large batch // for (int i = 0; i < 1000; ++i) { // large_batch->data.push_back( // std::make_shared("item_" + std::to_string(i)) // ); // } // Process with maximum parallelism // auto future = parallel_processor->RunAsync(large_batch); // auto result = future.get(); // All items processed in parallel ``` -------------------------------- ### Parallel Processing with AsyncNode in C++ Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Implements parallel processing using the AsyncNode. The ExecAsync method launches a new thread to perform an operation asynchronously, returning a std::future for the result. It handles StringData and simulates a delay. Dependencies include AsyncNode.h and FrameworkData. ```cpp #include "AsyncNode/AsyncNode.h" class ParallelProcessorNode : public AsyncNode { public: std::future> ExecAsync( std::shared_ptr prep_res) override { return std::async(std::launch::async, [prep_res]() { // CPU-intensive or I/O operation std::this_thread::sleep_for(std::chrono::seconds(1)); if (auto* input = prep_res->as()) { auto result = std::make_shared( "Processed in parallel: " + input->value ); return std::static_pointer_cast(result); } return prep_res; }); } }; // Usage auto async_node = std::make_shared(); auto input = std::make_shared("data"); // Start async processing auto future = async_node->RunAsync(input); // Do other work while processing... std::cout << "Processing in background..." << std::endl; // Get the result when ready auto result = future.get(); ``` -------------------------------- ### Batch Processing with BatchNode in C++ Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Demonstrates batch processing using the BatchNode. The exec method processes a collection of items within a VectorData object. It iterates through the batch, transforms each StringData item, and returns a new VectorData with processed results. Dependencies include BatchNode.h, VectorData.h, and FrameworkData. ```cpp #include "BatchNode/BatchNode.h" #include "BatchNode/VectorData.h" class BatchTextProcessor : public BatchNode { public: std::shared_ptr exec(std::shared_ptr items) override { auto* batch = items->as(); if (!batch) { throw std::invalid_argument("Expected VectorData for batch processing"); } auto result = std::make_shared(); result->data.reserve(batch->data.size()); // Optimize memory allocation // Process each item for (const auto& item : batch->data) { if (auto* str_item = item->as()) { auto processed = std::make_shared( "Batch: " + str_item->value ); result->data.push_back(processed); } } return result; } }; // Usage auto batch_processor = std::make_shared(); // Create batch data auto batch = std::make_shared(); batch->data.push_back(std::make_shared("item1")); batch->data.push_back(std::make_shared("item2")); batch->data.push_back(std::make_shared("item3")); // Process the entire batch auto result = batch_processor->Execute(batch); ``` -------------------------------- ### Define Diagnostic System Example (CMake) Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/CMakeLists.txt This CMake snippet sets up an example executable 'diagnostic_system_example' to illustrate the usage of the diagnostic system. It links against the 'agentic_framework' library, providing access to diagnostic functionalities. ```cmake add_executable(diagnostic_system_example examples/DiagnosticSystemExample.cpp ) target_link_libraries(diagnostic_system_example PRIVATE agentic_framework ) configure_executable(diagnostic_system_example) ``` -------------------------------- ### C++ Coroutine Pipeline Processing Example Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/CONCURRENCY_GUIDE.md Demonstrates processing a pipeline of asynchronous nodes using C++20 coroutines and the `FrameworkDataAwaitable`. This function `process_pipeline_coroutine` showcases how to sequentially `co_await` the results from different `AsyncNode` instances, simplifying complex asynchronous workflows. ```cpp #ifdef __cpp_impl_coroutine Task> process_pipeline_coroutine( std::shared_ptr input) { auto node1 = std::make_shared(); auto node2 = std::make_shared(); auto node3 = std::make_shared(); // Process through pipeline using coroutines auto result1 = co_await FrameworkDataAwaitable{node1, input}; auto result2 = co_await FrameworkDataAwaitable{node2, result1}; auto result3 = co_await FrameworkDataAwaitable{node3, result2}; co_return result3; } #endif ``` -------------------------------- ### Exception Safety Best Practice: RAII (C++) Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Demonstrates exception safety using the RAII (Resource Acquisition Is Initialization) principle. The `SafeNode` class shows how `std::unique_ptr` automatically manages resource cleanup, even when exceptions are thrown during processing. This ensures that resources are reliably released, preventing leaks. ```cpp class SafeNode : public Node { public: std::shared_ptr Exec(std::shared_ptr prep_res) override { // ✅ Good: RAII and exception safety std::unique_ptr resource = acquire_resource(); try { auto result = process_with_resource(prep_res, resource.get()); return result; // Resource automatically cleaned up } catch (...) { // Resource automatically cleaned up by unique_ptr throw; } } }; ``` -------------------------------- ### AsyncBatchFlow Example - C++ Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/API_REFERENCE.md Demonstrates the creation and execution of an AsyncBatchFlow for processing large batches of data asynchronously. It involves setting up loader, processor, and saver nodes and running them with a batch of StringData. ```cpp #include "AsyncBatchFlow/AsyncBatchFlow.h" // Create async batch processing nodes auto async_batch_loader = std::make_shared(); auto async_batch_processor = std::make_shared(); auto async_batch_saver = std::make_shared(); // Set up async batch flow async_batch_loader->next(async_batch_processor, "loaded"); async_batch_processor->next(async_batch_saver, "processed"); // Create async batch flow auto async_batch_flow = std::make_shared(async_batch_loader); // Create large batch for async processing auto large_batch = std::make_shared(); for (int i = 0; i < 10000; ++i) { large_batch->data.push_back( std::make_shared("async_batch_item_" + std::to_string(i)) ); } // Process asynchronously auto future = async_batch_flow->RunAsync(large_batch); // Monitor progress or do other work std::cout << "Large batch processing in background..." << std::endl; // Get result when complete auto result = future.get(); ``` -------------------------------- ### Define Optimized Batch Processor Example (CMake) Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/CMakeLists.txt This CMake snippet defines an example executable named 'optimized_batch_example' showcasing the OptimizedBatchProcessor. It links against the 'agentic_framework' library, demonstrating its usage in a practical scenario. ```cmake add_executable(optimized_batch_example examples/OptimizedBatchProcessorExample.cpp ) target_link_libraries(optimized_batch_example PRIVATE agentic_framework ) configure_executable(optimized_batch_example) ``` -------------------------------- ### Define Async Timeout Example (CMake) Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/CMakeLists.txt This CMake configuration defines an example executable 'async_timeout_example' that demonstrates asynchronous operations with timeouts. It links against the 'agentic_framework' library for core functionality. ```cmake add_executable(async_timeout_example examples/AsyncTimeoutExample.cpp ) target_link_libraries(async_timeout_example PRIVATE agentic_framework ) configure_executable(async_timeout_example) ``` -------------------------------- ### BatchNode Usage Example: Processing Collections in C++ Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/API_REFERENCE.md Provides an example of how to use the BatchNode class. It illustrates creating a concrete implementation `BatchProcessingNode` that processes a `VectorData` object. The example shows how to construct a batch of string items and then execute the batch processing logic. ```cpp #include "BatchNode/BatchNode.h" #include "BatchNode/VectorData.h" class BatchProcessingNode : public BatchNode { public: std::shared_ptr exec(std::shared_ptr items) override { auto* batch = items->as(); if (!batch) { throw std::invalid_argument("Expected VectorData for batch processing"); } auto result = std::make_shared(); // Process each item in the batch for (const auto& item : batch->data) { if (auto* str_item = item->as()) { auto processed = std::make_shared( "Batch processed: " + str_item->value ); result->data.push_back(processed); } } return result; } }; // Usage auto batch_node = std::make_shared(); // Create batch data auto batch = std::make_shared(); batch->data.push_back(std::make_shared("item1")); batch->data.push_back(std::make_shared("item2")); batch->data.push_back(std::make_shared("item3")); // Process batch auto result = batch_node->Execute(batch); ``` -------------------------------- ### Install Build Dependencies for C++ Agentic Framework Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/BUILD.md Installs required build tools like CMake, Ninja, Clang-tidy, and Cppcheck on Ubuntu/Debian and macOS systems. These are essential for compiling and analyzing the C++ code. ```bash # Ubuntu/Debian sudo apt install cmake ninja-build clang-tidy cppcheck # macOS brew install cmake ninja clang-format cppcheck ``` -------------------------------- ### CMake: Configure Agentic Framework Build and Installation Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/CMakeLists.txt Configures build settings, including include directories, threading support, target properties, and library aliasing. It also defines installation rules for the library, headers, and CMake export files, ensuring proper packaging and discoverability for consumers. ```cmake target_include_directories(agentic_framework PUBLIC $ $ ) # Add threading support for async components find_package(Threads REQUIRED) target_link_libraries(agentic_framework PUBLIC Threads::Threads) # Set target properties set_target_properties(agentic_framework PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR} # Remove PUBLIC_HEADER line - it's redundant with FILE_SET HEADERS ) # Create alias for better namespacing add_library(agentic::framework ALIAS agentic_framework) # Installation configuration include(GNUInstallDirs) install(TARGETS agentic_framework EXPORT agentic_frameworkTargets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} FILE_SET HEADERS DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/agentic_framework ) # Install export file install(EXPORT agentic_frameworkTargets FILE agentic_frameworkTargets.cmake NAMESPACE agentic:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/agentic_framework ) ``` -------------------------------- ### AsyncParallelBatchFlow Usage Example - C++ Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/API_REFERENCE.md Illustrates the usage of AsyncParallelBatchFlow for high-throughput parallel processing of massive batches. It sets up splitter, processor, and merger nodes and demonstrates running the flow asynchronously with an optional timeout. ```cpp #include "AsyncParallelBatchFlow/AsyncParallelBatchFlow.h" // Create parallel batch processing nodes auto parallel_batch_splitter = std::make_shared(); auto parallel_batch_processor = std::make_shared(); auto parallel_batch_merger = std::make_shared(); // Set up parallel batch flow parallel_batch_splitter->next(parallel_batch_processor, "split"); parallel_batch_processor->next(parallel_batch_merger, "processed"); // Create parallel batch flow auto parallel_flow = std::make_shared(parallel_batch_splitter); // Create massive batch for parallel processing auto massive_batch = std::make_shared(); for (int i = 0; i < 100000; ++i) { massive_batch->data.push_back( std::make_shared("parallel_item_" + std::to_string(i)) ); } // Process with maximum parallelism auto start_time = std::chrono::high_resolution_clock::now(); auto future = parallel_flow->RunAsync(massive_batch); // Optional: Add timeout for very large batches try { auto result = parallel_flow->RunAsyncWithTimeout( massive_batch, std::chrono::minutes(5) ).get(); auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast( end_time - start_time ); std::cout << "Processed 100,000 items in " << duration.count() << " seconds using parallel batch flow" << std::endl; } catch (const std::runtime_error& e) { std::cout << "Parallel batch processing timed out: " << e.what() << std::endl; } ``` -------------------------------- ### Async Batch Processing with C++ Agentic Framework Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/API_REFERENCE.md Demonstrates how to implement asynchronous batch processing using the AsyncBatchNode in C++. This example processes items sequentially within the async call and requires the FrameworkData and VectorData classes. ```cpp #include "AsyncBatchNode/AsyncBatchNode.h" #include "BatchNode/VectorData.h" class AsyncBatchProcessingNode : public AsyncBatchNode { private: std::shared_ptr exec(std::shared_ptr items) override { auto* batch = items->as(); if (!batch) { throw std::invalid_argument("Expected VectorData for async batch processing"); } auto result = std::make_shared(); result->data.reserve(batch->data.size()); // Process each item asynchronously (in sequence within this method) for (const auto& item : batch->data) { if (auto* str_item = item->as()) { // Simulate async processing std::this_thread::sleep_for(std::chrono::milliseconds(10)); auto processed = std::make_shared( "Async batch processed: " + str_item->value ); result->data.push_back(processed); } } return result; } }; // Usage auto async_batch_node = std::make_shared(); auto batch = std::make_shared(); batch->data.push_back(std::make_shared("async_item1")); batch->data.push_back(std::make_shared("async_item2")); // Process asynchronously auto future = async_batch_node->RunAsync(batch); auto result = future.get(); // Non-blocking batch processing ``` -------------------------------- ### C++20 Coroutine Async Node Example Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/CONCURRENCY_GUIDE.md An example `CoroutineAsyncNode` class that inherits from `AsyncNode` and uses C++20 coroutines for asynchronous processing. It demonstrates `co_await` for suspending execution and `co_return` for yielding results. The `ExecAsync` method wraps the coroutine execution in a `std::async` task. ```cpp #ifdef __cpp_impl_coroutine class CoroutineAsyncNode : public AsyncNode { public: Task> process_async_coroutine( std::shared_ptr input) { // Simulate async work co_await std::suspend_for(std::chrono::milliseconds(100)); if (auto* str_data = input->as()) { auto result = std::make_shared( "Coroutine processed: " + str_data->value ); co_return std::static_pointer_cast(result); } throw std::invalid_argument("Expected StringData"); } std::future> ExecAsync( std::shared_ptr prep_res) override { return std::async(std::launch::async, [this, prep_res]() { auto task = process_async_coroutine(prep_res); // Wait for coroutine to complete while (!task.is_ready()) { std::this_thread::sleep_for(std::chrono::milliseconds(1)); } return task.get(); }); } }; #endif ``` -------------------------------- ### Demonstrate FrameworkData Immutability with Concurrent Reads Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/CONCURRENCY_GUIDE.md This C++ example illustrates the thread safety of immutable FrameworkData objects. It shows how multiple threads can concurrently read the same shared data without issues. The example uses `std::thread` and `std::shared_ptr` to manage data sharing safely. ```cpp #include "BaseNode/FrameworkData.h" #include #include #include #include #include // Assuming StringData is a concrete implementation of FrameworkData // and has a public 'value' member and 'as()' method. // For compilation, a mock definition might be needed if not provided. class StringData : public FrameworkData { public: std::string value; StringData(std::string val) : value(std::move(val)) {} template T* as() { return dynamic_cast(this); } // Add necessary virtual destructor and other base class requirements if StringData is part of a hierarchy }; class ImmutableDataExample { public: void demonstrate_immutable_data() { auto shared_data = std::make_shared("shared value"); std::vector readers; for (int i = 0; i < 10; ++i) { readers.emplace_back([shared_data, i]() { for (int j = 0; j < 1000; ++j) { std::string value = shared_data->value; // Thread-safe read if (auto* str_data = shared_data->as()) { // std::cout is not guaranteed to be thread-safe by default // In a real application, use a mutex or a thread-safe logger. // std::cout << "Thread " << i << " read: " << str_data->value << std::endl; } } }); } for (auto& reader : readers) { reader.join(); } } }; ``` -------------------------------- ### Run Performance Tests and Benchmarks (Bash) Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/tests/BatchProcessingPerformanceTestsREADME.md Command-line examples for executing performance tests and benchmarks for the C++ agentic framework. These commands allow running all tests, specific tests, or benchmarks with configurable options like time limits and filters. ```bash # Run all performance tests ./build/run_tests --gtest_filter="BatchProcessingPerformanceTest.*" # Run specific performance test ./build/run_tests --gtest_filter="BatchProcessingPerformanceTest.MemoryAllocationPatterns" # Run all benchmarks ./build/run_benchmarks # Run benchmarks with specific time limit ./build/run_benchmarks --benchmark_min_time=0.1s # Run specific benchmark ./build/run_benchmarks --benchmark_filter="BatchCreation.*" ``` -------------------------------- ### Build with Build Script (Bash) Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/BUILD.md This snippet shows how to use the provided `build.sh` script for configuring, building, and testing the Agentic Framework. The script offers commands like `configure`, `build`, `test`, and `ci` for streamlined development and CI integration. Ensure the script is executable on Unix-like systems. ```bash # Make the script executable (Unix-like systems) chmod +x build.sh # Configure, build, and test with default settings ./build.sh configure ./build.sh build ./build.sh test # Or run everything at once ./build.sh ci ``` -------------------------------- ### Create and Execute a Basic Flow Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/API_REFERENCE.md Demonstrates how to create nodes, define a sequential flow with branching logic, and execute it with input data and parameters. Requires the 'Flow.h' header. ```cpp #include "Flow/Flow.h" // Create nodes auto node1 = std::make_shared(); auto node2 = std::make_shared(); auto node3 = std::make_shared(); // Set up flow node1->next(node2, "success"); node1->next(node3, "error"); node2->next(node3, "default"); // Create and execute flow auto flow = std::make_shared(node1); auto input = std::make_shared("flow input"); std::map> flow_params; flow_params["global_config"] = std::make_shared("production"); auto result = flow->orch(input, flow_params); ``` -------------------------------- ### Standard Development Workflow (Bash) Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/BUILD.md This snippet outlines the standard development workflow using CMake presets. It includes configuring the project for debugging, building the target, and running tests with verbose output for failures. This is suitable for day-to-day development. ```bash # Configure for development cmake --preset=debug # Build cmake --build --preset=debug # Run tests ctest --preset=debug --output-on-failure ``` -------------------------------- ### Thread Safety with Shared Mutex in C++ Agentic Framework Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Shows how to implement thread-safe access to shared data within an AsyncNode using std::shared_mutex. It demonstrates using std::shared_lock for read operations and std::unique_lock for write operations. ```cpp class ThreadSafeNode : public AsyncNode { private: mutable std::shared_mutex data_mutex_; std::map cached_data_; public: std::string get_cached_value(const std::string& key) const { // ✅ Good: Shared lock for read operations std::shared_lock lock(data_mutex_); auto it = cached_data_.find(key); return it != cached_data_.end() ? it->second : ""; } void set_cached_value(const std::string& key, const std::string& value) { // ✅ Good: Unique lock for write operations std::unique_lock lock(data_mutex_); cached_data_[key] = value; } }; ``` -------------------------------- ### Async Flow Coordination (C++) Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Illustrates how to coordinate asynchronous nodes within an `AsyncFlow`. The `orch` method is overridden to detect and execute `AsyncNode` instances, waiting for their completion before proceeding. This ensures proper sequencing of operations in a complex flow. Depends on `AsyncFlow.h`. ```cpp #include "AsyncFlow/AsyncFlow.h" class AsyncFlow : public Flow { public: // Override to handle async nodes in the flow std::shared_ptr orch( std::shared_ptr shared, const std::map>& params = {}) override { auto current_node = startNode; auto current_data = shared; while (current_node) { // Check if node is async if (auto* async_node = dynamic_cast(current_node.get())) { // Handle async execution auto future = async_node->RunAsync(current_data); current_data = future.get(); // Wait for completion } else { // Handle sync execution current_data = current_node->Execute(current_data); } // Get next node (simplified) current_node = GetNextNode(current_node, "default"); } return current_data; } }; ``` -------------------------------- ### Create Custom TextProcessorNode in C++ Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Defines a custom node 'TextProcessorNode' inheriting from 'Node'. This node processes string data, supporting operations like uppercase, lowercase, and reverse. It includes parameter handling, execution logic, and a fallback mechanism for errors. ```cpp #include "Node/Node.h" #include "Flow/StringData.h" #include #include class TextProcessorNode : public Node { public: // Constructor with retry configuration TextProcessorNode() : Node(3, 1000) { // 3 retries, 1 second wait // Set default parameters std::map> default_params; default_params["operation"] = std::make_shared("uppercase"); setParam(std::move(default_params)); } std::shared_ptr Exec(std::shared_ptr prep_res) override { // Get the operation parameter auto operation_param = getParam("operation"); std::string operation = "uppercase"; // default if (auto* op_data = operation_param->as()) { operation = op_data->value; } // Process the input if (auto* input = prep_res->as()) { std::string result = input->value; if (operation == "uppercase") { std::transform(result.begin(), result.end(), result.begin(), ::toupper); } else if (operation == "lowercase") { std::transform(result.begin(), result.end(), result.begin(), ::tolower); } else if (operation == "reverse") { std::reverse(result.begin(), result.end()); } else { throw std::invalid_argument("Unknown operation: " + operation); } return std::make_shared(result); } throw std::invalid_argument("Expected StringData input"); } // Optional: Custom fallback for failed operations std::shared_ptr exec_fallback( const std::shared_ptr& prep_res, std::exception_ptr eptr) const override { try { std::rethrow_exception(eptr); } catch (const std::exception& e) { std::cerr << "TextProcessor failed: " << e.what() << std::endl; // Return original input as fallback return prep_res; } } }; ``` -------------------------------- ### CMake: Fetch and Configure Google Test and Benchmark Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/CMakeLists.txt Enables testing by setting up Google Test and Google Benchmark. It uses `FetchContent` to download these testing frameworks from their respective GitHub repositories and makes them available for use in the build. ```cmake # Google Test and Google Benchmark enable_testing() include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG v1.14.0 ) FetchContent_Declare( googlebenchmark GIT_REPOSITORY https://github.com/google/benchmark.git GIT_TAG v1.8.3 ) FetchContent_MakeAvailable(googletest googlebenchmark) ``` -------------------------------- ### Static Analysis Workflow (Bash) Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/BUILD.md This snippet explains how to enable and run static analysis tools like `clang-tidy` and `cppcheck` using CMake presets. It covers configuring with the `static-analysis` preset, building to trigger analysis during compilation, or running it separately via `make` within the build directory. ```bash # Configure with static analysis cmake --preset=static-analysis # Build (will run clang-tidy and cppcheck during compilation) cmake --build --preset=static-analysis # Or run static analysis separately cd build/static-analysis make static_analysis ``` -------------------------------- ### Safe Operations with Result Types in C++ Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/GETTING_STARTED.md Demonstrates using 'Result' types for safe operations, specifically a 'safe_divide' function that returns a 'Result' indicating success with a 'FrameworkData' pointer or failure with a 'FrameworkError'. The 'SafeMathNode' class shows how to chain these operations, with automatic error propagation and handling. ```cpp #include "BaseNode/Result.h" using namespace framework; // Function that can fail Result> safe_divide(double a, double b) { if (b == 0.0) { return FrameworkError::invalid_argument("Division by zero"); } auto result = std::make_shared>(a / b); return std::static_pointer_cast(result); } // Node using Result types class SafeMathNode : public Node { public: std::shared_ptr Exec(std::shared_ptr prep_res) override { // Chain operations with automatic error propagation auto result = extract_numbers(prep_res) .flat_map([](auto numbers) { return safe_divide(numbers.first, numbers.second); }) .map([](auto data) { std::cout << "Division successful" << std::endl; return data; }) .map_error([](const FrameworkError& e) { std::cerr << "Math operation failed: " << e.what() << std::endl; return e; }); if (result.has_value()) { return result.value(); } else { // Convert error to exception (or handle differently) throw result.error(); } } private: Result> extract_numbers(std::shared_ptr data) { // Implementation to extract two numbers from input data // Return Result with pair of numbers or error return std::make_pair(10.0, 2.0); // Simplified } }; ``` -------------------------------- ### Thread-Safe Processing with Immutable Data in C++ Source: https://github.com/utkarsh-cpu/cpp-agentic-framework/blob/master/docs/CONCURRENCY_GUIDE.md Presents a C++ example demonstrating thread-safe data processing by favoring immutable data structures. The `ImmutableProcessingNode` class ensures thread safety by creating new data instances rather than modifying existing ones. ```cpp // ✅ Good: Immutable data is inherently thread-safe class ImmutableProcessingNode : public Node { public: std::shared_ptr Exec(std::shared_ptr prep_res) override { // Create new data instead of modifying existing if (auto* input = prep_res->as()) { return std::make_shared("Processed: " + input->value); } return prep_res; } }; ```