Skip to main content

encounter_argumentation/
knowledge.rs

1//! Trait for providing per-character argumentation capabilities.
2
3use std::collections::HashMap;
4
5/// A character's position in an argument: which scheme they invoke and with what bindings.
6#[derive(Debug, Clone)]
7pub struct ArgumentPosition {
8    /// Snake-case scheme key (e.g., "argument_from_expert_opinion").
9    pub scheme_key: String,
10    /// Slot bindings for the scheme (e.g., {"expert": "alice", "domain": "military"}).
11    pub bindings: HashMap<String, String>,
12    /// Relative preference weight. Higher = stronger conviction. Range: [0.0, 1.0].
13    pub preference_weight: f64,
14}
15
16/// Provides per-character argumentation capabilities.
17pub trait ArgumentKnowledge: Send + Sync {
18    /// What arguments can `actor` make in support of performing `action`?
19    fn arguments_for_action(
20        &self,
21        actor: &str,
22        action_name: &str,
23        action_bindings: &HashMap<String, String>,
24    ) -> Vec<ArgumentPosition>;
25
26    /// What counter-arguments can `actor` make against `action`?
27    fn counter_arguments(
28        &self,
29        actor: &str,
30        action_name: &str,
31        proposer_arguments: &[ArgumentPosition],
32    ) -> Vec<ArgumentPosition>;
33}
34
35/// Test helper: returns pre-configured argument positions.
36#[derive(Debug, Default)]
37pub struct StaticKnowledge {
38    entries: Vec<StaticEntry>,
39}
40
41#[derive(Debug)]
42struct StaticEntry {
43    actor: String,
44    action: String,
45    is_counter: bool,
46    positions: Vec<ArgumentPosition>,
47}
48
49impl StaticKnowledge {
50    /// Create an empty knowledge base.
51    pub fn new() -> Self {
52        Self::default()
53    }
54
55    /// Register arguments for an actor performing an action.
56    pub fn add_arguments(&mut self, actor: &str, action: &str, positions: Vec<ArgumentPosition>) {
57        self.entries.push(StaticEntry {
58            actor: actor.into(),
59            action: action.into(),
60            is_counter: false,
61            positions,
62        });
63    }
64
65    /// Register counter-arguments for an actor against an action.
66    pub fn add_counter_arguments(
67        &mut self,
68        actor: &str,
69        action: &str,
70        positions: Vec<ArgumentPosition>,
71    ) {
72        self.entries.push(StaticEntry {
73            actor: actor.into(),
74            action: action.into(),
75            is_counter: true,
76            positions,
77        });
78    }
79}
80
81impl ArgumentKnowledge for StaticKnowledge {
82    fn arguments_for_action(
83        &self,
84        actor: &str,
85        action_name: &str,
86        _action_bindings: &HashMap<String, String>,
87    ) -> Vec<ArgumentPosition> {
88        self.entries
89            .iter()
90            .filter(|e| e.actor == actor && e.action == action_name && !e.is_counter)
91            .flat_map(|e| e.positions.clone())
92            .collect()
93    }
94
95    fn counter_arguments(
96        &self,
97        actor: &str,
98        action_name: &str,
99        _proposer_arguments: &[ArgumentPosition],
100    ) -> Vec<ArgumentPosition> {
101        self.entries
102            .iter()
103            .filter(|e| e.actor == actor && e.action == action_name && e.is_counter)
104            .flat_map(|e| e.positions.clone())
105            .collect()
106    }
107}