capability-example 0.1.0

A framework for managing skill tree growth and configuration using automated and manual strategies, ideal for AI-driven environments.
Documentation
// ---------------- [ File: capability-example/src/manual_flow_strategy.rs ]
crate::ix!();

/// A `FlowStrategy` for purely manual usage:
///  - We write queries to a file and tell the user "PLEASE RUN THIS QUERY MANUALLY"
///  - We do *not* call any language model client ourselves
pub struct ManualFlowStrategy {
    query_output_path: PathBuf,
}

impl From<PathBuf> for ManualFlowStrategy {

    fn from(query_output_path: PathBuf) -> Self {
        Self {
            query_output_path
        }
    }
}

impl ManualFlowStrategy {

    /// Helper to write the query to the file and print instructions
    #[instrument(level = "trace", skip_all)]
    async fn write_query_and_instruct_user(
        &self,
        query_str: &str,
        instruction: &str,
    ) -> Result<(), ManualGrowerFlowError> {
        let mut file = File::create(&self.query_output_path).await?;
        file.write_all(query_str.as_bytes()).await?;
        save_string_to_clipboard(query_str)?;
        info!("PLEASE RUN THIS QUERY MANUALLY:\n\n{}\n", query_str);
        info!("{}", instruction);
        Ok(())
    }
}

#[async_trait]
impl GrowerFlowStrategy for ManualFlowStrategy {

    #[instrument(level = "trace", skip(self, partial, grower_inputs))]
    async fn fill_justified_tree_configuration(
        &self,
        partial: &PartiallyGrownModel,
        grower_inputs: &GrowerInputs,
    ) -> Result<Option<JustifiedGrowerTreeConfiguration>, ManualGrowerFlowError> {
        info!("Missing JustifiedGrowerTreeConfiguration. Generating query for user...");
        let query_str =
            GrowerModel::grower_tree_configuration_generation_query_string(grower_inputs);
        let instruction = "Afterwards, add the result under `maybe_ungrown_justified_grower_tree_configuration` in the partial JSON and re-run.";

        self.write_query_and_instruct_user(&query_str, instruction)
            .await?;
        Ok(None)
    }

    #[instrument(level = "trace", skip(self, partial, grower_inputs, tree_conf))]
    async fn fill_justified_string_skeleton(
        &self,
        partial: &PartiallyGrownModel,
        grower_inputs: &GrowerInputs,
        tree_conf: &JustifiedGrowerTreeConfiguration,
    ) -> Result<Option<JustifiedStringSkeleton>, ManualGrowerFlowError> {
        info!("We have a JustifiedGrowerTreeConfiguration but no JustifiedStringSkeleton. Generating query...");
        let query_str =
            GrowerModel::string_skeleton_generation_query_string(grower_inputs, tree_conf);
        let instruction = "Afterwards, place the result under `maybe_ungrown_justified_string_skeleton` and re-run.";

        self.write_query_and_instruct_user(&query_str, instruction)
            .await?;
        Ok(None)
    }

    #[instrument(level = "trace", skip(self, partial, grower_inputs, tree_conf, stripped_skel))]
    async fn fill_core_string_skeleton(
        &self,
        partial: &PartiallyGrownModel,
        grower_inputs: &GrowerInputs,
        tree_conf: &JustifiedGrowerTreeConfiguration,
        stripped_skel: &StrippedStringSkeleton,
    ) -> Result<Option<CoreStringSkeleton>, ManualGrowerFlowError> {
        info!("We have a StrippedStringSkeleton but no CoreStringSkeleton. Generating query...");
        let query_str = GrowerModel::core_string_skeleton_generation_query_string(
            grower_inputs,
            tree_conf,
            stripped_skel,
        );
        let instruction = "Afterwards, place the result under `maybe_ungrown_core_string_skeleton` and re-run.";

        self.write_query_and_instruct_user(&query_str, instruction)
            .await?;
        Ok(None)
    }

    #[instrument(level = "trace", skip(self, partial, grower_inputs, tree_conf, core_skel))]
    async fn fill_annotated_leaf_holder_expansions(
        &self,
        partial: &PartiallyGrownModel,
        grower_inputs: &GrowerInputs,
        tree_conf: &JustifiedGrowerTreeConfiguration,
        core_skel: &CoreStringSkeleton,
    ) -> Result<Option<AnnotatedLeafHolderExpansions>, ManualGrowerFlowError> {
        info!("We have a CoreStringSkeleton but no AnnotatedLeafHolderExpansions. Generating query...");
        let query_str = GrowerModel::annotated_leaf_holder_expansions_generation_query_string(
            grower_inputs,
            tree_conf,
            core_skel,
        );
        let instruction = "Afterwards, place the result under `maybe_ungrown_annotated_leaf_holder_expansions` and re-run.";

        self.write_query_and_instruct_user(&query_str, instruction)
            .await?;
        Ok(None)
    }
}