stemedb/crates/stemedb-sim/src/strategy.rs
jordan 55349845d0 refactor: Split all files to enforce 500-line max
Break monolith source files into focused modules:
- stemedb-core/types.rs → types/ directory (assertion, source, gold_standard, etc.)
- stemedb-storage: audit_store, quota_store, trust_rank_store, vector_index, vote_store → module directories
- stemedb-ingest/worker.rs → worker/ with separate test modules
- stemedb-query: engine, materializer, query → module directories
- stemedb-lens: epoch_aware, skeptic → module directories
- stemedb-sim/lib.rs → agent, arenas/, helpers, runner, strategy, types
- stemedb-api/tests: integration_tests → http_basic, http_validation, http_epoch, http_pipeline
- stemedb-api/tests: e2e_flow_test → e2e_full_pipeline, e2e_lens_resolution
- stemedb-query/tests: e2e_pipeline → e2e_pipeline + e2e_decay

Also adds new features: gold standard verification, escalation handlers,
admin endpoints, concept hierarchy spec, arena roadmap, and Go SDK.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 01:13:45 -07:00

197 lines
5.9 KiB
Rust

//! Agent strategy patterns for simulation.
//!
//! Defines different agent behaviors (Scientist, Troll, Believer) and
//! the framework for strategy-driven simulation.
use stemedb_core::types::{Hash, ObjectValue};
/// Specification for creating agents with a particular strategy.
#[derive(Debug, Clone, Copy)]
pub struct AgentSpec {
/// Number of agents to create with this strategy.
pub count: usize,
/// The strategy type for these agents.
pub strategy: StrategyType,
}
/// Available strategy types for agents.
#[derive(Debug, Clone, Copy)]
pub enum StrategyType {
/// Scientific agent: creates high-confidence assertions.
Scientist,
/// Troll agent: creates low-confidence contradictions.
Troll,
/// Believer agent: primarily votes, occasionally creates assertions.
Believer,
}
/// Metrics tracking for a strategy.
#[derive(Debug, Clone, Default)]
pub struct StrategyMetrics {
/// Number of assertions created.
pub assertions_created: usize,
/// Number of votes cast.
pub votes_cast: usize,
/// Number of queries executed.
pub queries_executed: usize,
/// Number of skip actions taken.
pub skips: usize,
}
/// World state visible to agents when making decisions.
#[derive(Debug, Clone)]
pub struct WorldState {
/// Current simulation tick.
pub tick: usize,
/// Existing assertions (hash, subject, predicate, object, confidence).
pub existing_assertions: Vec<(Hash, String, String, ObjectValue, f32)>,
/// Vote summaries (assertion_hash, total_weight).
pub vote_summaries: Vec<(Hash, f32)>,
/// Total number of agents in the simulation.
pub agent_count: usize,
}
/// Actions an agent can take in a simulation tick.
#[derive(Debug, Clone)]
pub enum AgentAction {
/// Create a new assertion.
Assert {
/// The subject entity.
subject: String,
/// The predicate/relation.
predicate: String,
/// The object value.
object: ObjectValue,
},
/// Cast a vote for an assertion.
Vote {
/// Hash of the assertion to vote on.
assertion_hash: Hash,
/// Vote weight (0.0 to 1.0).
weight: f32,
},
/// Execute a query.
Query {
/// The subject to query.
subject: String,
/// The predicate to query.
predicate: String,
},
/// Skip this turn.
Skip,
}
/// Trait defining agent strategy behavior.
pub trait AgentStrategy: Send {
/// Human-readable strategy name.
fn name(&self) -> &str;
/// Base confidence level for assertions created by this strategy.
fn base_confidence(&self) -> f32;
/// Decide what action to take given the current world state.
fn decide_action(&self, world: &WorldState) -> AgentAction;
}
/// Scientist strategy: creates high-confidence assertions.
struct ScientistStrategy;
impl AgentStrategy for ScientistStrategy {
fn name(&self) -> &str {
"Scientist"
}
fn base_confidence(&self) -> f32 {
0.9
}
fn decide_action(&self, world: &WorldState) -> AgentAction {
let subject = format!("Entity_{}", world.tick);
let predicate = "has_property".to_string();
let object = ObjectValue::Text(format!("value_{}", world.tick));
AgentAction::Assert { subject, predicate, object }
}
}
/// Troll strategy: creates low-confidence contradictions.
struct TrollStrategy;
impl AgentStrategy for TrollStrategy {
fn name(&self) -> &str {
"Troll"
}
fn base_confidence(&self) -> f32 {
0.3
}
fn decide_action(&self, world: &WorldState) -> AgentAction {
// If there are existing assertions, contradict one
if !world.existing_assertions.is_empty() {
let target = &world.existing_assertions[world.tick % world.existing_assertions.len()];
return AgentAction::Assert {
subject: target.1.clone(),
predicate: target.2.clone(),
object: ObjectValue::Text(format!("fake_value_{}", world.tick)),
};
}
// Otherwise create a generic low-confidence assertion
AgentAction::Assert {
subject: format!("TrollEntity_{}", world.tick),
predicate: "dubious_claim".to_string(),
object: ObjectValue::Text("unverified".to_string()),
}
}
}
/// Believer strategy: primarily votes, occasionally creates assertions.
struct BelieverStrategy;
impl AgentStrategy for BelieverStrategy {
fn name(&self) -> &str {
"Believer"
}
fn base_confidence(&self) -> f32 {
0.7
}
fn decide_action(&self, world: &WorldState) -> AgentAction {
// Believers prefer to vote on existing high-confidence assertions
if !world.existing_assertions.is_empty() {
// Find highest confidence assertion
if let Some((hash, _, _, _, confidence)) = world
.existing_assertions
.iter()
.max_by(|a, b| a.4.partial_cmp(&b.4).unwrap_or(std::cmp::Ordering::Equal))
{
if *confidence > 0.5 {
return AgentAction::Vote { assertion_hash: *hash, weight: 1.0 };
}
}
}
// Occasionally create an assertion or skip
if world.tick % 3 == 0 {
AgentAction::Assert {
subject: format!("BeliefEntity_{}", world.tick),
predicate: "trusted_fact".to_string(),
object: ObjectValue::Text(format!("trusted_value_{}", world.tick)),
}
} else {
AgentAction::Skip
}
}
}
/// Create a strategy instance for the given type.
pub fn create_strategy(strategy_type: StrategyType) -> Box<dyn AgentStrategy> {
match strategy_type {
StrategyType::Scientist => Box::new(ScientistStrategy),
StrategyType::Troll => Box::new(TrollStrategy),
StrategyType::Believer => Box::new(BelieverStrategy),
}
}