discourse-sim 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. discourse_sim-0.1.0/LICENSE +21 -0
  2. discourse_sim-0.1.0/MANIFEST.in +8 -0
  3. discourse_sim-0.1.0/PKG-INFO +286 -0
  4. discourse_sim-0.1.0/README.md +246 -0
  5. discourse_sim-0.1.0/discourse_sim/__init__.py +29 -0
  6. discourse_sim-0.1.0/discourse_sim/agents/__init__.py +2 -0
  7. discourse_sim-0.1.0/discourse_sim/agents/agent.py +129 -0
  8. discourse_sim-0.1.0/discourse_sim/config.py +222 -0
  9. discourse_sim-0.1.0/discourse_sim/core.py +333 -0
  10. discourse_sim-0.1.0/discourse_sim/simulation/__init__.py +2 -0
  11. discourse_sim-0.1.0/discourse_sim/simulation/engine.py +381 -0
  12. discourse_sim-0.1.0/discourse_sim/timeline/__init__.py +2 -0
  13. discourse_sim-0.1.0/discourse_sim/timeline/timeline.py +79 -0
  14. discourse_sim-0.1.0/discourse_sim/tools/__init__.py +2 -0
  15. discourse_sim-0.1.0/discourse_sim/tools/search_tools.py +78 -0
  16. discourse_sim-0.1.0/discourse_sim/utils/__init__.py +2 -0
  17. discourse_sim-0.1.0/discourse_sim/utils/dataframes.py +89 -0
  18. discourse_sim-0.1.0/discourse_sim.egg-info/PKG-INFO +286 -0
  19. discourse_sim-0.1.0/discourse_sim.egg-info/SOURCES.txt +26 -0
  20. discourse_sim-0.1.0/discourse_sim.egg-info/dependency_links.txt +1 -0
  21. discourse_sim-0.1.0/discourse_sim.egg-info/requires.txt +16 -0
  22. discourse_sim-0.1.0/discourse_sim.egg-info/top_level.txt +1 -0
  23. discourse_sim-0.1.0/examples/custom_agent_kinds.py +58 -0
  24. discourse_sim-0.1.0/examples/dublin_march.py +88 -0
  25. discourse_sim-0.1.0/examples/minimal_usage.py +35 -0
  26. discourse_sim-0.1.0/pyproject.toml +59 -0
  27. discourse_sim-0.1.0/setup.cfg +4 -0
  28. discourse_sim-0.1.0/setup.py +25 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 dreji18
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,8 @@
1
+ include README.md
2
+ include LICENSE
3
+ include pyproject.toml
4
+ recursive-include discourse_sim *.py
5
+ recursive-include examples *.py
6
+ exclude app.py
7
+ prune data
8
+ prune .streamlit
@@ -0,0 +1,286 @@
1
+ Metadata-Version: 2.4
2
+ Name: discourse-sim
3
+ Version: 0.1.0
4
+ Summary: LLM-augmented Agent-Based Social Simulation for modelling public discourse dynamics following a critical real-world event.
5
+ Author: dreji18
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/dreji18/discourse_sim
8
+ Project-URL: Repository, https://github.com/dreji18/discourse_sim
9
+ Project-URL: Bug Tracker, https://github.com/dreji18/discourse_sim/issues
10
+ Keywords: agent-based-modelling,social-simulation,LLM,public-discourse,opinion-dynamics,ABM,polarisation,NLP
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
14
+ Classifier: Topic :: Sociology
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: License :: OSI Approved :: MIT License
20
+ Classifier: Operating System :: OS Independent
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: numpy>=1.24
25
+ Requires-Dist: networkx>=3.0
26
+ Requires-Dist: tqdm>=4.64
27
+ Requires-Dist: pandas>=2.0
28
+ Requires-Dist: langchain-core>=0.1
29
+ Requires-Dist: langchain-community>=0.0.20
30
+ Requires-Dist: duckduckgo-search>=4.0
31
+ Provides-Extra: ollama
32
+ Requires-Dist: langchain-ollama>=0.1; extra == "ollama"
33
+ Provides-Extra: dev
34
+ Requires-Dist: pytest; extra == "dev"
35
+ Requires-Dist: twine; extra == "dev"
36
+ Requires-Dist: build; extra == "dev"
37
+ Requires-Dist: ruff; extra == "dev"
38
+ Dynamic: license-file
39
+ Dynamic: requires-python
40
+
41
+ # discourse_sim
42
+
43
+ **LLM-augmented Agent-Based Social Simulation** for modelling public discourse dynamics following a critical real-world event.
44
+
45
+ Agents observe live news, reason about it, post to a simulated social network, and update multidimensional beliefs through peer influence and news salience — all powered by a local Ollama LLM.
46
+
47
+ ---
48
+
49
+ ## Installation
50
+
51
+ ```bash
52
+ # Install the package
53
+ pip install -e .
54
+
55
+ # Install with Ollama support (recommended)
56
+ pip install -e ".[ollama]"
57
+
58
+ # Pull the default model
59
+ ollama pull mistral:7b-instruct-q4_0
60
+ ```
61
+
62
+ **All dependencies:**
63
+ ```bash
64
+ pip install langchain-core langchain-community langchain-ollama \
65
+ duckduckgo-search networkx numpy tqdm pandas openpyxl
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Quick Start
71
+
72
+ ```python
73
+ from discourse_sim import DiscourseSimulation
74
+
75
+ sim = DiscourseSimulation(
76
+ critical_event=(
77
+ "In late April 2025, Dublin saw a large anti-immigration march "
78
+ "from the Garden of Remembrance to the Custom House, with thousands "
79
+ "protesting immigration levels and housing pressure..."
80
+ ),
81
+ event_date="2025-04-26",
82
+ topic="immigration in Ireland",
83
+ n_agents=100,
84
+ n_days=15,
85
+ )
86
+
87
+ sim.run()
88
+ df = sim.to_dataframe() # one row per agent per day
89
+ df.to_excel("output.xlsx", index=False)
90
+ ```
91
+
92
+ ---
93
+
94
+ ## All Parameters
95
+
96
+ ### Required
97
+
98
+ | Parameter | Type | Description |
99
+ |---|---|---|
100
+ | `critical_event` | `str` | Plain-text description of the event injected into every agent prompt on every day |
101
+ | `event_date` | `str` | ISO date `"YYYY-MM-DD"` — this becomes Day 0 |
102
+ | `topic` | `str` | Subject domain, e.g. `"immigration in Ireland"`. Anchors search queries and scoring prompts |
103
+
104
+ ### Agent Population
105
+
106
+ | Parameter | Type | Default | Description |
107
+ |---|---|---|---|
108
+ | `n_agents` | `int` | `100` | Number of synthetic agents |
109
+ | `n_days` | `int` | `15` | Simulation duration in days |
110
+ | `agent_distribution` | `dict` | Ireland 2025 empirical split | Proportions of each agent kind — must sum to 1.0 |
111
+ | `kind_priors` | `dict` | `DEFAULT_KIND_PRIORS` | Prior distributions for belief/attitude initialisation per kind |
112
+
113
+ **Default distribution (Ireland 2025):**
114
+ ```python
115
+ {"centrist": 0.45, "far_right": 0.20, "pro_imm": 0.25, "media": 0.10}
116
+ ```
117
+
118
+ ### Timeline
119
+
120
+ | Parameter | Type | Default | Description |
121
+ |---|---|---|---|
122
+ | `timeline` | `dict[int, str]` | `None` | Optional explicit daily news entries keyed by 0-based day index. Missing days auto-generated. If `None`, all days use live search. |
123
+
124
+ **Example:**
125
+ ```python
126
+ timeline={
127
+ 0: "[VERIFIED] The march took place at the Garden of Remembrance...",
128
+ 4: "[VERIFIED] Government announced a deportation flight...",
129
+ }
130
+ ```
131
+
132
+ Any day not in the dict falls back to an auto-generated entry. Agents search live news on every day regardless of timeline.
133
+
134
+ ### LLM & Network
135
+
136
+ | Parameter | Type | Default | Description |
137
+ |---|---|---|---|
138
+ | `ollama_model` | `str` | `"mistral:7b-instruct-q4_0"` | Any locally pulled Ollama model |
139
+ | `temperature` | `float` | `0.75` | Post generation temperature |
140
+ | `use_llm_scoring` | `bool` | `True` | If `False`, uses keyword heuristic for attitude scoring |
141
+ | `network_k` | `int` | `6` | Watts-Strogatz nearest-neighbour count |
142
+ | `network_p` | `float` | `0.3` | Watts-Strogatz rewiring probability |
143
+ | `network_seed` | `int` | `42` | Reproducibility seed for network and agents |
144
+
145
+ ### Belief Update Keywords
146
+
147
+ | Parameter | Type | Default | Description |
148
+ |---|---|---|---|
149
+ | `threat_keywords` | `list[str]` | See config.py | Words in daily news that trigger `security_threat_belief` increase and `exposure` accumulation |
150
+ | `humanitarian_keywords` | `list[str]` | See config.py | Words that trigger `humanitarian_belief` increase |
151
+
152
+ Override these when simulating non-immigration topics:
153
+ ```python
154
+ threat_keywords=["eviction", "homeless", "unaffordable", "crisis"],
155
+ humanitarian_keywords=["social housing", "rights", "family", "support"],
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Outputs
161
+
162
+ ```python
163
+ sim.run()
164
+
165
+ # Single DataFrame — one row per agent per day (recommended for analysis)
166
+ df = sim.to_dataframe()
167
+
168
+ # All three DataFrames
169
+ dfs = sim.to_dataframes()
170
+ dfs["history"] # one row per timestep — aggregate metrics
171
+ dfs["agents"] # one row per agent per timestep — full belief state
172
+ dfs["messages"] # one row per agent per timestep — posts + beliefs merged
173
+ ```
174
+
175
+ ### Column reference — `df_messages`
176
+
177
+ | Column | Description |
178
+ |---|---|
179
+ | `t` / `date` | Day index and calendar date |
180
+ | `agent_id` / `kind` / `quirk` | Agent identity |
181
+ | `message` | The generated social media post |
182
+ | `interpreted_score` | LLM-scored stance [-1, +1] |
183
+ | `attitude` | Agent attitude at end of day t |
184
+ | `mood` | Agent mood at end of day t |
185
+ | `exposure` | Cumulative threat narrative exposure |
186
+ | `economic_threat_belief` | Economic threat sub-belief |
187
+ | `cultural_threat_belief` | Cultural threat sub-belief |
188
+ | `security_threat_belief` | Security threat sub-belief |
189
+ | `humanitarian_belief` | Humanitarian weight sub-belief |
190
+ | `avg_attitude` | Population mean attitude that day |
191
+ | `polarization` | Mean edge-level attitude divergence |
192
+ | `news_summary` | First 120 chars of daily news entry |
193
+
194
+ ---
195
+
196
+ ## Custom Agent Kinds
197
+
198
+ Add any agent kind by extending `DEFAULT_KIND_PRIORS`:
199
+
200
+ ```python
201
+ from discourse_sim import DiscourseSimulation
202
+ from discourse_sim.config import DEFAULT_KIND_PRIORS
203
+
204
+ custom_priors = {
205
+ **DEFAULT_KIND_PRIORS,
206
+ "nationalist": {
207
+ "attitude": (0.55, 0.95),
208
+ "economic_threat": (0.2, 0.6),
209
+ "cultural_threat": (0.7, 1.0),
210
+ "humanitarian": (-0.6, 0.0),
211
+ "openness": (0.1, 0.35),
212
+ "emotional_react": (0.5, 0.85),
213
+ },
214
+ }
215
+
216
+ sim = DiscourseSimulation(
217
+ ...,
218
+ agent_distribution={"centrist": 0.35, "nationalist": 0.30, "pro_imm": 0.35},
219
+ kind_priors=custom_priors,
220
+ )
221
+ ```
222
+
223
+ ---
224
+
225
+ ## Architecture
226
+
227
+ ```
228
+ discourse_sim/
229
+ ├── __init__.py # Public API: DiscourseSimulation
230
+ ├── core.py # DiscourseSimulation class — orchestrator
231
+ ├── config.py # SimConfig dataclass — all parameters + validation
232
+ ├── agents/
233
+ │ └── agent.py # Agent dataclass + make_agents() factory
234
+ ├── tools/
235
+ │ └── search_tools.py # make_tools() — search, memory, sentiment
236
+ ├── timeline/
237
+ │ └── timeline.py # Timeline class — user-supplied + auto-generated
238
+ ├── simulation/
239
+ │ └── engine.py # generate_message(), score_message(), update_beliefs(), run_loop()
240
+ └── utils/
241
+ └── dataframes.py # build_dataframes() — history/agents/messages
242
+ ```
243
+
244
+ **Per-day flow for each agent:**
245
+
246
+ ```
247
+ OBSERVE → search_event_news(query) # live DuckDuckGo
248
+ → recall_agent_memory(posts_json) # last 5 posts
249
+
250
+ THINK → build prompt: event + profile + memory + search result + today's news
251
+
252
+ ACT → LLM call → post text (max 40 words)
253
+
254
+ SCORE → LLM call (temp=0.0) → float in [-1, +1]
255
+
256
+ UPDATE → news salience → sub-beliefs
257
+ → peer pull → attitude pressure
258
+ → mood shock → affective state
259
+ → inertia → resistance to change
260
+ → composite → attitude(t)
261
+ ```
262
+
263
+ ---
264
+
265
+ ## Examples
266
+
267
+ | File | Description |
268
+ |---|---|
269
+ | `examples/dublin_march.py` | Full reproduction of the original Dublin April 2025 experiment |
270
+ | `examples/minimal_usage.py` | Minimal usage — no timeline, live search only |
271
+ | `examples/custom_agent_kinds.py` | Adding a custom `nationalist` kind with its own priors |
272
+
273
+ ---
274
+
275
+ ## Citation
276
+
277
+ If you use this package in research, please cite:
278
+
279
+ ```
280
+ @software{discourse_sim,
281
+ title = {discourse\_sim: LLM-Augmented Agent-Based Social Simulation of Discourse Dynamics},
282
+ author = {dreji18},
283
+ year = {2026},
284
+ note = {Python package}
285
+ }
286
+ ```
@@ -0,0 +1,246 @@
1
+ # discourse_sim
2
+
3
+ **LLM-augmented Agent-Based Social Simulation** for modelling public discourse dynamics following a critical real-world event.
4
+
5
+ Agents observe live news, reason about it, post to a simulated social network, and update multidimensional beliefs through peer influence and news salience — all powered by a local Ollama LLM.
6
+
7
+ ---
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ # Install the package
13
+ pip install -e .
14
+
15
+ # Install with Ollama support (recommended)
16
+ pip install -e ".[ollama]"
17
+
18
+ # Pull the default model
19
+ ollama pull mistral:7b-instruct-q4_0
20
+ ```
21
+
22
+ **All dependencies:**
23
+ ```bash
24
+ pip install langchain-core langchain-community langchain-ollama \
25
+ duckduckgo-search networkx numpy tqdm pandas openpyxl
26
+ ```
27
+
28
+ ---
29
+
30
+ ## Quick Start
31
+
32
+ ```python
33
+ from discourse_sim import DiscourseSimulation
34
+
35
+ sim = DiscourseSimulation(
36
+ critical_event=(
37
+ "In late April 2025, Dublin saw a large anti-immigration march "
38
+ "from the Garden of Remembrance to the Custom House, with thousands "
39
+ "protesting immigration levels and housing pressure..."
40
+ ),
41
+ event_date="2025-04-26",
42
+ topic="immigration in Ireland",
43
+ n_agents=100,
44
+ n_days=15,
45
+ )
46
+
47
+ sim.run()
48
+ df = sim.to_dataframe() # one row per agent per day
49
+ df.to_excel("output.xlsx", index=False)
50
+ ```
51
+
52
+ ---
53
+
54
+ ## All Parameters
55
+
56
+ ### Required
57
+
58
+ | Parameter | Type | Description |
59
+ |---|---|---|
60
+ | `critical_event` | `str` | Plain-text description of the event injected into every agent prompt on every day |
61
+ | `event_date` | `str` | ISO date `"YYYY-MM-DD"` — this becomes Day 0 |
62
+ | `topic` | `str` | Subject domain, e.g. `"immigration in Ireland"`. Anchors search queries and scoring prompts |
63
+
64
+ ### Agent Population
65
+
66
+ | Parameter | Type | Default | Description |
67
+ |---|---|---|---|
68
+ | `n_agents` | `int` | `100` | Number of synthetic agents |
69
+ | `n_days` | `int` | `15` | Simulation duration in days |
70
+ | `agent_distribution` | `dict` | Ireland 2025 empirical split | Proportions of each agent kind — must sum to 1.0 |
71
+ | `kind_priors` | `dict` | `DEFAULT_KIND_PRIORS` | Prior distributions for belief/attitude initialisation per kind |
72
+
73
+ **Default distribution (Ireland 2025):**
74
+ ```python
75
+ {"centrist": 0.45, "far_right": 0.20, "pro_imm": 0.25, "media": 0.10}
76
+ ```
77
+
78
+ ### Timeline
79
+
80
+ | Parameter | Type | Default | Description |
81
+ |---|---|---|---|
82
+ | `timeline` | `dict[int, str]` | `None` | Optional explicit daily news entries keyed by 0-based day index. Missing days auto-generated. If `None`, all days use live search. |
83
+
84
+ **Example:**
85
+ ```python
86
+ timeline={
87
+ 0: "[VERIFIED] The march took place at the Garden of Remembrance...",
88
+ 4: "[VERIFIED] Government announced a deportation flight...",
89
+ }
90
+ ```
91
+
92
+ Any day not in the dict falls back to an auto-generated entry. Agents search live news on every day regardless of timeline.
93
+
94
+ ### LLM & Network
95
+
96
+ | Parameter | Type | Default | Description |
97
+ |---|---|---|---|
98
+ | `ollama_model` | `str` | `"mistral:7b-instruct-q4_0"` | Any locally pulled Ollama model |
99
+ | `temperature` | `float` | `0.75` | Post generation temperature |
100
+ | `use_llm_scoring` | `bool` | `True` | If `False`, uses keyword heuristic for attitude scoring |
101
+ | `network_k` | `int` | `6` | Watts-Strogatz nearest-neighbour count |
102
+ | `network_p` | `float` | `0.3` | Watts-Strogatz rewiring probability |
103
+ | `network_seed` | `int` | `42` | Reproducibility seed for network and agents |
104
+
105
+ ### Belief Update Keywords
106
+
107
+ | Parameter | Type | Default | Description |
108
+ |---|---|---|---|
109
+ | `threat_keywords` | `list[str]` | See config.py | Words in daily news that trigger `security_threat_belief` increase and `exposure` accumulation |
110
+ | `humanitarian_keywords` | `list[str]` | See config.py | Words that trigger `humanitarian_belief` increase |
111
+
112
+ Override these when simulating non-immigration topics:
113
+ ```python
114
+ threat_keywords=["eviction", "homeless", "unaffordable", "crisis"],
115
+ humanitarian_keywords=["social housing", "rights", "family", "support"],
116
+ ```
117
+
118
+ ---
119
+
120
+ ## Outputs
121
+
122
+ ```python
123
+ sim.run()
124
+
125
+ # Single DataFrame — one row per agent per day (recommended for analysis)
126
+ df = sim.to_dataframe()
127
+
128
+ # All three DataFrames
129
+ dfs = sim.to_dataframes()
130
+ dfs["history"] # one row per timestep — aggregate metrics
131
+ dfs["agents"] # one row per agent per timestep — full belief state
132
+ dfs["messages"] # one row per agent per timestep — posts + beliefs merged
133
+ ```
134
+
135
+ ### Column reference — `df_messages`
136
+
137
+ | Column | Description |
138
+ |---|---|
139
+ | `t` / `date` | Day index and calendar date |
140
+ | `agent_id` / `kind` / `quirk` | Agent identity |
141
+ | `message` | The generated social media post |
142
+ | `interpreted_score` | LLM-scored stance [-1, +1] |
143
+ | `attitude` | Agent attitude at end of day t |
144
+ | `mood` | Agent mood at end of day t |
145
+ | `exposure` | Cumulative threat narrative exposure |
146
+ | `economic_threat_belief` | Economic threat sub-belief |
147
+ | `cultural_threat_belief` | Cultural threat sub-belief |
148
+ | `security_threat_belief` | Security threat sub-belief |
149
+ | `humanitarian_belief` | Humanitarian weight sub-belief |
150
+ | `avg_attitude` | Population mean attitude that day |
151
+ | `polarization` | Mean edge-level attitude divergence |
152
+ | `news_summary` | First 120 chars of daily news entry |
153
+
154
+ ---
155
+
156
+ ## Custom Agent Kinds
157
+
158
+ Add any agent kind by extending `DEFAULT_KIND_PRIORS`:
159
+
160
+ ```python
161
+ from discourse_sim import DiscourseSimulation
162
+ from discourse_sim.config import DEFAULT_KIND_PRIORS
163
+
164
+ custom_priors = {
165
+ **DEFAULT_KIND_PRIORS,
166
+ "nationalist": {
167
+ "attitude": (0.55, 0.95),
168
+ "economic_threat": (0.2, 0.6),
169
+ "cultural_threat": (0.7, 1.0),
170
+ "humanitarian": (-0.6, 0.0),
171
+ "openness": (0.1, 0.35),
172
+ "emotional_react": (0.5, 0.85),
173
+ },
174
+ }
175
+
176
+ sim = DiscourseSimulation(
177
+ ...,
178
+ agent_distribution={"centrist": 0.35, "nationalist": 0.30, "pro_imm": 0.35},
179
+ kind_priors=custom_priors,
180
+ )
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Architecture
186
+
187
+ ```
188
+ discourse_sim/
189
+ ├── __init__.py # Public API: DiscourseSimulation
190
+ ├── core.py # DiscourseSimulation class — orchestrator
191
+ ├── config.py # SimConfig dataclass — all parameters + validation
192
+ ├── agents/
193
+ │ └── agent.py # Agent dataclass + make_agents() factory
194
+ ├── tools/
195
+ │ └── search_tools.py # make_tools() — search, memory, sentiment
196
+ ├── timeline/
197
+ │ └── timeline.py # Timeline class — user-supplied + auto-generated
198
+ ├── simulation/
199
+ │ └── engine.py # generate_message(), score_message(), update_beliefs(), run_loop()
200
+ └── utils/
201
+ └── dataframes.py # build_dataframes() — history/agents/messages
202
+ ```
203
+
204
+ **Per-day flow for each agent:**
205
+
206
+ ```
207
+ OBSERVE → search_event_news(query) # live DuckDuckGo
208
+ → recall_agent_memory(posts_json) # last 5 posts
209
+
210
+ THINK → build prompt: event + profile + memory + search result + today's news
211
+
212
+ ACT → LLM call → post text (max 40 words)
213
+
214
+ SCORE → LLM call (temp=0.0) → float in [-1, +1]
215
+
216
+ UPDATE → news salience → sub-beliefs
217
+ → peer pull → attitude pressure
218
+ → mood shock → affective state
219
+ → inertia → resistance to change
220
+ → composite → attitude(t)
221
+ ```
222
+
223
+ ---
224
+
225
+ ## Examples
226
+
227
+ | File | Description |
228
+ |---|---|
229
+ | `examples/dublin_march.py` | Full reproduction of the original Dublin April 2025 experiment |
230
+ | `examples/minimal_usage.py` | Minimal usage — no timeline, live search only |
231
+ | `examples/custom_agent_kinds.py` | Adding a custom `nationalist` kind with its own priors |
232
+
233
+ ---
234
+
235
+ ## Citation
236
+
237
+ If you use this package in research, please cite:
238
+
239
+ ```
240
+ @software{discourse_sim,
241
+ title = {discourse\_sim: LLM-Augmented Agent-Based Social Simulation of Discourse Dynamics},
242
+ author = {dreji18},
243
+ year = {2026},
244
+ note = {Python package}
245
+ }
246
+ ```
@@ -0,0 +1,29 @@
1
+ """
2
+ discourse_sim
3
+ =============
4
+ LLM-augmented Agent-Based Social Simulation for modelling
5
+ public discourse dynamics following a critical real-world event.
6
+
7
+ Quick start
8
+ -----------
9
+ from discourse_sim import DiscourseSimulation
10
+
11
+ sim = DiscourseSimulation(
12
+ critical_event="In November 2023, Dublin city centre saw a major riot...",
13
+ event_date="2023-11-23",
14
+ n_agents=100,
15
+ n_days=15,
16
+ agent_distribution={"centrist": 0.45, "far_right": 0.20,
17
+ "pro_imm": 0.25, "media": 0.10},
18
+ topic="immigration in Ireland",
19
+ ollama_model="mistral:7b-instruct-q4_0",
20
+ )
21
+
22
+ sim.run()
23
+ df = sim.to_dataframe()
24
+ """
25
+
26
+ from discourse_sim.core import DiscourseSimulation
27
+
28
+ __all__ = ["DiscourseSimulation"]
29
+ __version__ = "0.1.0"
@@ -0,0 +1,2 @@
1
+ from discourse_sim.agents.agent import Agent, make_agents, QUIRK_OPTIONS
2
+ __all__ = ["Agent", "make_agents", "QUIRK_OPTIONS"]