crate::ix!();
#[derive(
Debug,
Clone,
PartialEq,
Getters,
Builder,
Serialize,
Deserialize,
SaveLoad,
)]
#[builder(pattern = "owned", setter(into))]
#[getset(get = "pub")]
pub struct GrowerModel {
grower_inputs: GrowerInputs,
#[serde(alias="maybe_ungrown_justified_grower_tree_configuration")]
justified_grower_tree_configuration: JustifiedGrowerTreeConfiguration,
#[serde(alias="maybe_ungrown_justified_string_skeleton")]
justified_string_skeleton: JustifiedStringSkeleton,
#[serde(alias="maybe_ungrown_stripped_string_skeleton")]
stripped_string_skeleton: StrippedStringSkeleton,
#[serde(alias="maybe_ungrown_core_string_skeleton")]
core_string_skeleton: CoreStringSkeleton,
#[serde(alias="maybe_ungrown_annotated_leaf_holder_expansions")]
annotated_leaf_holder_expansions: AnnotatedLeafHolderExpansions,
}
impl GrowerModel {
pub async fn new(
seed: PartiallyGrownModel,
client: &GrowerLanguageModelClient,
) -> Result<Self,GrowerModelGenerationError> {
seed.validate();
let justified_grower_tree_configuration = seed.maybe_grow_justified_tree_configuration(client).await?;
let justified_string_skeleton = seed.maybe_grow_justified_string_skeleton(client).await?;
let stripped_string_skeleton = StrippedStringSkeleton::from(justified_string_skeleton.clone());
let core_string_skeleton = seed.maybe_grow_core_string_skeleton(client).await?;
let annotated_leaf_holder_expansions = seed.maybe_grow_annotated_leaf_holder_expansions(client).await?;
Ok(Self {
grower_inputs: seed.grower_inputs().clone().unwrap(),
justified_grower_tree_configuration,
justified_string_skeleton,
stripped_string_skeleton,
core_string_skeleton,
annotated_leaf_holder_expansions,
})
}
#[instrument(level = "trace", skip_all)]
pub fn finalize_from_valid_partial(
partial: PartiallyGrownModel,
) -> Result<Self, GrowerModelGenerationError> {
partial.validate().map_err(GrowerModelGenerationError::InvalidPartial)?;
let grower_inputs = partial
.grower_inputs()
.clone()
.expect("Validation guarantees grower_inputs is present");
let justified_grower_tree_configuration = partial
.maybe_ungrown_justified_grower_tree_configuration()
.clone()
.expect("Validation guarantees this is present");
let justified_string_skeleton = partial
.maybe_ungrown_justified_string_skeleton()
.clone()
.expect("Validation guarantees this is present");
let stripped_string_skeleton = partial
.maybe_ungrown_stripped_string_skeleton()
.clone()
.expect("Validation guarantees this is present");
let core_string_skeleton = partial
.maybe_ungrown_core_string_skeleton()
.clone()
.expect("Validation guarantees this is present");
let annotated_leaf_holder_expansions = partial
.maybe_ungrown_annotated_leaf_holder_expansions()
.clone()
.expect("Validation guarantees this is present");
Ok(GrowerModel {
grower_inputs,
justified_grower_tree_configuration,
justified_string_skeleton,
stripped_string_skeleton,
core_string_skeleton,
annotated_leaf_holder_expansions,
})
}
pub async fn show_all_generation_queries(&self) {
trace!("Preparing to show all generation queries for GrowerModel");
let query_cfg = Self::grower_tree_configuration_generation_query_string(
self.grower_inputs(),
);
info!("GrowerTreeConfiguration query:\n{query_cfg}");
let query_skel = Self::string_skeleton_generation_query_string(
self.grower_inputs(),
self.justified_grower_tree_configuration(),
);
info!("StringSkeleton query:\n{query_skel}");
let query_core = Self::core_string_skeleton_generation_query_string(
self.grower_inputs(),
self.justified_grower_tree_configuration(),
self.stripped_string_skeleton(),
);
info!("CoreStringSkeleton query:\n{query_core}");
let query_leaf = Self::annotated_leaf_holder_expansions_generation_query_string(
self.grower_inputs(),
self.justified_grower_tree_configuration(),
self.core_string_skeleton(),
);
info!("AnnotatedLeafHolderExpansions query:\n{query_leaf}");
trace!("Done showing all generation queries for GrowerModel");
}
}
impl PartiallyGrownModel {
pub async fn maybe_grow_justified_tree_configuration(
&self,
client: &GrowerLanguageModelClient,
) -> Result<JustifiedGrowerTreeConfiguration, GrowerModelGenerationError> {
trace!("maybe_grow_justified_tree_configuration called with partial: {:?}", self);
match &self.maybe_ungrown_justified_grower_tree_configuration() {
Some(cfg) => {
debug!("maybe_ungrown_justified_grower_tree_configuration already present");
Ok(cfg.clone())
}
None => {
debug!("maybe_ungrown_justified_grower_tree_configuration not present, generating now");
let generated = match GrowerModel::generate_grower_tree_configuration(
client,
self.grower_inputs().as_ref().unwrap()
).await {
Ok(g) => g,
Err(e) => {
GrowerModel::handle_grower_tree_configuration_generation_error(
e,
client,
self.grower_inputs().as_ref().unwrap()
).await?
}
};
Ok(generated)
}
}
}
pub async fn maybe_grow_justified_string_skeleton(
&self,
client: &GrowerLanguageModelClient,
) -> Result<JustifiedStringSkeleton, GrowerModelGenerationError> {
trace!("maybe_grow_justified_string_skeleton called with partial: {:?}", self);
match &self.maybe_ungrown_justified_string_skeleton() {
Some(skel) => {
debug!("maybe_ungrown_justified_string_skeleton already present");
Ok(skel.clone())
}
None => {
debug!("maybe_ungrown_justified_string_skeleton not present, generating now");
let tree_conf = self
.maybe_ungrown_justified_grower_tree_configuration()
.as_ref()
.expect("Validation should have prevented missing JustifiedGrowerTreeConfiguration");
let generated = match GrowerModel::generate_string_skeleton(
client,
self.grower_inputs().as_ref().unwrap(),
tree_conf
).await {
Ok(g) => g,
Err(e) => {
GrowerModel::handle_string_skeleton_generation_error(
e,
client,
self.grower_inputs().as_ref().unwrap(),
tree_conf
).await?
}
};
Ok(generated)
}
}
}
pub async fn maybe_grow_core_string_skeleton(
&self,
client: &GrowerLanguageModelClient,
) -> Result<CoreStringSkeleton, GrowerModelGenerationError> {
trace!("maybe_grow_core_string_skeleton called with partial: {:?}", self);
match &self.maybe_ungrown_core_string_skeleton() {
Some(exp) => {
debug!("maybe_ungrown_core_string_skeleton already present");
Ok(exp.clone())
}
None => {
debug!("maybe_ungrown_core_string_skeleton not present, generating now");
let tree_conf = self
.maybe_ungrown_justified_grower_tree_configuration()
.as_ref()
.expect("Validation should have prevented missing JustifiedGrowerTreeConfiguration");
let skeleton = self
.maybe_ungrown_justified_string_skeleton()
.as_ref()
.expect("Validation should have prevented missing JustifiedStringSkeleton");
let stripped = StrippedStringSkeleton::from(skeleton.clone());
let generated = match GrowerModel::generate_core_string_skeleton(
client,
self.grower_inputs().as_ref().unwrap(),
tree_conf,
&stripped
).await {
Ok(g) => g,
Err(e) => {
GrowerModel::handle_core_string_skeleton_generation_error(
e,
client,
self.grower_inputs().as_ref().unwrap(),
tree_conf,
skeleton,
&stripped
).await?
}
};
Ok(generated)
}
}
}
pub async fn maybe_grow_annotated_leaf_holder_expansions(
&self,
client: &GrowerLanguageModelClient,
) -> Result<AnnotatedLeafHolderExpansions, GrowerModelGenerationError> {
trace!("maybe_grow_annotated_leaf_holder_expansions called with partial: {:?}", self);
match &self.maybe_ungrown_annotated_leaf_holder_expansions() {
Some(exp) => {
debug!("maybe_ungrown_annotated_leaf_holder_expansions already present");
Ok(exp.clone())
}
None => {
debug!("maybe_ungrown_annotated_leaf_holder_expansions not present, generating now");
let tree_conf = self
.maybe_ungrown_justified_grower_tree_configuration()
.as_ref()
.expect("Validation should have prevented missing JustifiedGrowerTreeConfiguration");
let skeleton = self
.maybe_ungrown_justified_string_skeleton()
.as_ref()
.expect("Validation should have prevented missing JustifiedStringSkeleton");
let stripped = StrippedStringSkeleton::from(skeleton.clone());
let core_string_skeleton = self
.maybe_ungrown_core_string_skeleton()
.as_ref()
.expect("Validation should have prevented missing CoreStringSkeleton");
let generated = match GrowerModel::generate_annotated_leaf_holder_expansions(
client,
self.grower_inputs().as_ref().unwrap(),
tree_conf,
&stripped,
core_string_skeleton
).await {
Ok(g) => g,
Err(e) => {
GrowerModel::handle_annotated_leaf_holder_expansion_generation_error(
e,
client,
self.grower_inputs().as_ref().unwrap(),
tree_conf,
skeleton,
&stripped,
core_string_skeleton
).await?
}
};
Ok(generated)
}
}
}
}
#[cfg(test)]
#[disable]
mod verify_show_all_generation_queries {
use super::*;
use std::collections::HashMap;
#[traced_test]
async fn it_displays_all_generation_queries_without_error() {
trace!("Starting test: it_displays_all_generation_queries_without_error");
let grower_inputs = GrowerInputsBuilder::default()
.target(CLASSIC_SKILL)
.global_environment_descriptor(YOU_ARE_HERE.to_string())
.sub_environments(
CLASSIC_SUB_ENVIRONMENTS
.iter()
.map(|s| s.to_string())
.collect::<Vec<_>>()
)
.neighbors(
CLASSIC_SKILL_NEIGHBORS
.iter()
.map(|s| s.to_string())
.collect::<Vec<_>>()
)
.build()
.expect("Failed to build GrowerInputs for test");
let level_skipping_config = LevelSkippingConfigurationBuilder::default()
.leaf_probability_per_level(vec![0.15, 0.3])
.build()
.expect("Failed building LevelSkippingConfiguration");
let weighted_branching_config = WeightedBranchingConfigurationBuilder::default()
.mean(3)
.variance(1)
.build()
.expect("Failed building WeightedBranchingConfiguration");
let tree_level_specific_config = TreeLevelSpecificConfigurationBuilder::default()
.breadth_per_level(vec![2, 4])
.density_per_level(vec![2, 3])
.build()
.expect("Failed building TreeLevelSpecificConfiguration");
let capstone_config = CapstoneGenerationConfigurationBuilder::default()
.mode(CapstoneMode::Probabilistic)
.probability(0.2)
.build()
.expect("Failed building CapstoneGenerationConfiguration");
let ai_conf = AiTreeBranchingConfidenceConfigurationBuilder::default()
.base_factor(2)
.factor_multiplier(1.5)
.build()
.expect("Failed building AiTreeBranchingConfidenceConfiguration");
let tree_config = GrowerTreeConfigurationBuilder::default()
.depth(3)
.breadth(2)
.density(2)
.leaf_granularity(0.8)
.balance_symmetry(0.4)
.complexity(ConfigurationComplexity::Balanced)
.level_specific(Some(tree_level_specific_config))
.weighted_branching(Some(weighted_branching_config))
.level_skipping(Some(level_skipping_config))
.capstone(Some(capstone_config))
.ordering(Some(SubBranchOrdering::Alphabetical))
.ai_confidence(Some(ai_conf))
.aggregator_preference(0.7)
.allow_early_leaves(true)
.partial_subbranch_probability(0.3)
.tree_expansion_policy(
TreeExpansionPolicy::Weighted(
WeightedNodeVariantPolicyBuilder::default()
.aggregator_weight(0.4)
.dispatch_weight(0.4)
.leaf_holder_weight(0.2)
.build()
.expect("Failed building WeightedNodeVariantPolicy")
)
)
.aggregator_depth_limit(Some(5))
.dispatch_depth_limit(Some(4))
.leaf_min_depth(Some(1))
.build()
.expect("Failed to build GrowerTreeConfiguration");
let justified_grower_tree_configuration = JustifiedGrowerTreeConfigurationBuilder::default()
.item(tree_config)
.justification(
GrowerTreeConfigurationJustification {
depth_justification: "Depth=3 => moderate hierarchy.".to_string(),
breadth_justification: "Breadth=2 => keep it simpler at each level.".to_string(),
density_justification: "Density=2 => each leaf node spawns 2 variants.".to_string(),
leaf_granularity_justification: "0.8 => quite detailed leaves but not too big.".to_string(),
balance_symmetry_justification: "0.4 => partial symmetry only.".to_string(),
complexity_justification: ConfigurationComplexityJustification {
enum_variant_justification: "Using Balanced variant for middle-of-the-road complexity.".to_string(),
},
level_specific_justification: TreeLevelSpecificConfigurationJustification {
breadth_per_level_justification: "Level 0 => 2, Level 1 => 4 sub-branches".to_string(),
density_per_level_justification: "Level 0 => density=2, Level 1 => density=3".to_string(),
},
weighted_branching_justification: WeightedBranchingConfigurationJustification {
mean_justification: "Mean=3 => typical branching factor.".to_string(),
variance_justification: "Variance=1 => slight randomness in branching.".to_string(),
},
level_skipping_justification: LevelSkippingConfigurationJustification {
leaf_probability_per_level_justification: "At Level0 => p=0.15, Level1 => p=0.3 => some skipping.".to_string(),
},
capstone_justification: CapstoneGenerationConfigurationJustification {
mode_justification: CapstoneModeJustification {
enum_variant_justification: "Probabilistic => not always a capstone leaf.".to_string(),
},
probability_justification: "p=0.2 => about 1 in 5 leaves becomes capstone.".to_string(),
},
ordering_justification: SubBranchOrderingJustification {
enum_variant_justification: "Alphabetical ordering for sub-branches.".to_string(),
},
ai_confidence_justification: AiTreeBranchingConfidenceConfigurationJustification {
base_factor_justification: "Base=2 => expansions double in certain contexts.".to_string(),
factor_multiplier_justification: "1.5 => expansions ramp up more if AI is sure.".to_string(),
},
aggregator_preference_justification: "0.7 => aggregator nodes favored frequently.".to_string(),
allow_early_leaves_justification: "true => sub-branches can terminate earlier.".to_string(),
partial_subbranch_probability_justification: "0.3 => some sub-branches appear optionally.".to_string(),
tree_expansion_policy_justification: TreeExpansionPolicyJustification {
enum_variant_justification: "Weighted aggregator=0.4, dispatch=0.4, leaf=0.2 => variety.".to_string(),
},
aggregator_depth_limit_justification: "No aggregator deeper than level=5.".to_string(),
dispatch_depth_limit_justification: "Stop dispatch deeper than level=4.".to_string(),
leaf_min_depth_justification: "Leaf-holders not before depth=1.".to_string(),
}
)
.confidence(
GrowerTreeConfigurationConfidence {
depth_confidence: 0.95,
breadth_confidence: 0.9,
density_confidence: 0.85,
leaf_granularity_confidence: 0.88,
balance_symmetry_confidence: 0.7,
complexity_confidence: ConfigurationComplexityConfidence {
enum_variant_confidence: 0.8,
},
level_specific_confidence: TreeLevelSpecificConfigurationConfidence {
breadth_per_level_confidence: 0.92,
density_per_level_confidence: 0.86,
},
weighted_branching_confidence: WeightedBranchingConfigurationConfidence {
mean_confidence: 0.77,
variance_confidence: 0.75,
},
level_skipping_confidence: LevelSkippingConfigurationConfidence {
leaf_probability_per_level_confidence: 0.65,
},
capstone_confidence: CapstoneGenerationConfigurationConfidence {
mode_confidence: CapstoneModeConfidence {
enum_variant_confidence: 0.6,
},
probability_confidence: 0.4,
},
ordering_confidence: SubBranchOrderingConfidence {
enum_variant_confidence: 0.9,
},
ai_confidence_confidence: AiTreeBranchingConfidenceConfigurationConfidence {
base_factor_confidence: 0.8,
factor_multiplier_confidence: 0.75,
},
aggregator_preference_confidence: 0.88,
allow_early_leaves_confidence: 0.82,
partial_subbranch_probability_confidence: 0.75,
tree_expansion_policy_confidence: TreeExpansionPolicyConfidence {
enum_variant_confidence: 0.85,
},
aggregator_depth_limit_confidence: 0.7,
dispatch_depth_limit_confidence: 0.65,
leaf_min_depth_confidence: 0.6,
}
)
.build()
.expect("Failed to build JustifiedGrowerTreeConfiguration");
let mut root_children = HashMap::new();
root_children.insert(
"AggregatorBranch".to_string(),
DispatchChildSpecBuilder::default()
.branch_selection_likelihood(100)
.build()
.expect("Failed building DispatchChildSpec")
);
root_children.insert(
"LeafBranch".to_string(),
DispatchChildSpecBuilder::default()
.branch_selection_likelihood(100)
.build()
.expect("Failed building leaf_holder DispatchChildSpec")
);
let root_node = StringSkeletonNode::Dispatch {
name: "RootDispatch".to_string(),
ordering: Some(SubBranchOrdering::Alphabetical),
children: root_children,
};
let mut aggregator_children = HashMap::new();
aggregator_children.insert(
"SubAggregator".to_string(),
AggregateChildSpecBuilder::default()
.psome_likelihood(80)
.optional(false)
.build()
.expect("Failed building aggregator child spec")
);
let aggregator_node = StringSkeletonNode::Aggregate {
name: "AggregatorBranch".to_string(),
ordering: None,
children: aggregator_children,
};
let leaf_node = StringSkeletonNode::LeafHolder {
name: "LeafBranch".to_string(),
ordering: None,
n_leaves: 10,
capstone: false,
};
let mut skel_map = HashMap::new();
skel_map.insert("root".to_string(), root_node);
skel_map.insert("AggregatorBranch".to_string(), aggregator_node);
skel_map.insert("LeafBranch".to_string(), leaf_node);
let string_skeleton = StringSkeletonBuilder::default()
.map(skel_map)
.build()
.expect("Failed to build StringSkeleton");
let justified_string_skeleton = JustifiedStringSkeletonBuilder::default()
.item(string_skeleton)
.justification(
StringSkeletonJustification {
map_justification: "Multiple branches illustrate distinct skill pathways.".to_string(),
}
)
.confidence(
StringSkeletonConfidence {
map_confidence: 0.85,
}
)
.build()
.expect("Failed to build JustifiedStringSkeleton");
let stripped_string_skeleton = StrippedStringSkeleton::from(&justified_string_skeleton);
let core_aggregate_node = CoreSkeletalAggregateNodeBuilder::default()
.name("CoreAggregateExample".to_string())
.descriptor("An aggregator example in the core skeleton".to_string())
.children(vec![])
.build()
.expect("Failed building CoreSkeletalAggregateNode");
let core_dispatch_node = CoreSkeletalDispatchNodeBuilder::default()
.name("CoreDispatchExample".to_string())
.descriptor("A dispatch example in the core skeleton".to_string())
.children(vec![])
.build()
.expect("Failed building CoreSkeletalDispatchNode");
let core_leaf_node = CoreSkeletalLeafHolderNodeBuilder::default()
.name("CoreLeafHolderExample".to_string())
.descriptor("A leaf holder example in the core skeleton".to_string())
.leaves(vec!["leaf_a".to_string(), "leaf_b".to_string(), "leaf_c".to_string()])
.build()
.expect("Failed building CoreSkeletalLeafHolderNode");
let core_string_skeleton = CoreStringSkeletonBuilder::default()
.dispatch_nodes(vec![core_dispatch_node])
.aggregate_nodes(vec![core_aggregate_node])
.leaf_holder_nodes(vec![core_leaf_node])
.build()
.expect("Failed to build CoreStringSkeleton");
let annotated_leaf_holder_node = AnnotatedLeafHolderNodeBuilder::default()
.leaf_holder_name("CoreLeafHolderExample".to_string())
.annotated_leaves(vec![
AnnotatedLeafBuilder::default()
.leaf_name("leaf_a".to_string())
.leaf_descriptor("This is an advanced skill technique.".to_string())
.build()
.expect("Failed building leaf_a"),
AnnotatedLeafBuilder::default()
.leaf_name("leaf_b".to_string())
.leaf_descriptor("A specialized sub-skill extension.".to_string())
.build()
.expect("Failed building leaf_b"),
])
.build()
.expect("Failed building AnnotatedLeafHolderNode");
let annotated_leaf_holder_expansions = AnnotatedLeafHolderExpansionsBuilder::default()
.annotated_leaf_holders(vec![annotated_leaf_holder_node])
.build()
.expect("Failed to build AnnotatedLeafHolderExpansions");
let model = GrowerModel {
grower_inputs,
justified_grower_tree_configuration,
justified_string_skeleton,
stripped_string_skeleton,
core_string_skeleton,
annotated_leaf_holder_expansions,
};
model.show_all_generation_queries().await;
assert!(false);
}
}