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>
197 lines
5.9 KiB
Rust
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),
|
|
}
|
|
}
|