Vikram Vasudevan commited on
Commit
696dddf
·
1 Parent(s): 9239f05

compararive insights

Browse files
README.md CHANGED
@@ -19,260 +19,36 @@ The goal is not to “simulate everything”, but to build a configurable sandbo
19
  - **Bias experiments**: What happens to world stability when the population is biased toward “good nature” vs “bad nature”?
20
  - **Scarcity vs abundance**: How do shared natural resources shape inequality, wellbeing, cooperation/conflict, and longevity?
21
  - **Identity dynamics**: How do race/faith/beauty norms influence social networks and opportunity, and how do they compound over rebirth cycles?
22
- - **Randomness vs “engineering”**: Are outcomes explainable from explicit rules and parameters, or do they appear chaotic until you measure them?
23
- - **Philosophical lenses**: If we encode different schools of thought (e.g., Advaita, Vishishtadvaita, Buddhist frameworks) as rule sets, how do they change emergent behavior and “liberation” outcomes?
24
 
25
- ### High-level model (simple, measurable, extensible)
26
- To keep the simulation testable, each philosophical concept is mapped to something measurable.
 
 
 
27
 
 
28
  - **Soul**: immutable id; persists across lifetimes; carries karma forward.
29
- - **Person (a body/life)**: a soul embodied for one lifetime with traits, identity markers, wellbeing, and relationships.
30
- - **Karma**: a numeric score (or vector later) updated by actions and outcomes; influences rebirth initialization.
31
- - **Nature (good/bad bias)**: a trait like `moral_bias [-1, 1]` affecting decisions (cooperate, hoard, harm, help).
32
- - **Resources**: global pool with replenishment; agents compete/coordinate to consume/produce.
33
- - **Society**: group labels (race/faith) and norms (beauty) influencing trust, mate choice, cooperation, and conflict.
34
- - **Events**: stochastic shocks (disease, drought, opportunity, tragedy) parameterized and observable in logs.
35
- - **Philosophical school / worldview**: a configurable “lens” that changes how agents interpret self/other, attachment, ethics, and the karma→rebirth→liberation mechanics (implemented as a pluggable ruleset, not hard-coded into the engine).
36
 
37
- ### Bringing in philosophical schools of thought (planned)
38
- At some point this simulation should support multiple **worldviews** as first-class configuration, such as:
39
- - **Advaita (Adhvaitha)**: non-dual framing; emphasis on ignorance/knowledge; reduced self/other separation.
40
- - **Vishishtadvaita (Vishistadvaitha)**: qualified non-dual framing; enduring individuality in relation to the whole.
41
- - **Buddhist lenses**: no fixed self, dependent origination; attachment/craving as drivers of suffering; liberation as reduction of craving/ignorance.
42
-
43
- Implementation-wise, these won’t be treated as “religion labels” like `faith`. Instead, they act as **simulation rule modules** that can change:
44
- - **Decision policy**: cooperation vs hoarding vs harm vs help; attachment, compassion, renunciation as parameters.
45
- - **Suffering/wellbeing model**: how craving/aversion affects wellbeing beyond material resources.
46
- - **Karma semantics**: how actions update karma and which actions matter.
47
- - **Rebirth mapping**: how karma affects next-life traits and circumstances.
48
- - **Liberation / exit conditions** (optional): when a soul stops rebirthing (e.g., thresholds, convergent criteria, or explicit “moksha/nirvana” state in the model).
49
-
50
- The key constraint: we’ll keep the **core engine neutral** and make worldviews pluggable so we can run the same initial world under different lenses and compare outcomes.
51
-
52
- ### Why a phased approach
53
- This idea contains many interacting systems. If we build UI/visuals first, we’ll optimize for looks before we know the world model creates interesting behavior.
54
-
55
- So we build **engine-first**, prove the simulation produces meaningful metrics and repeatable experiments, then layer visualization and richer social dynamics.
56
-
57
- ## Phased roadmap
58
- Each phase should end with something runnable and measurable.
59
-
60
- ### Phase 0 — Foundations (scaffolding + repeatability)
61
- - Basic repo structure and packaging
62
- - Single config object (or YAML/JSON) that fully defines a run
63
- - Deterministic seeding for reproducible scenarios
64
- - Logging/tracing of key events
65
-
66
- ### Phase 1 — Core life-cycle engine (V1 target)
67
- - A world with a **fixed soul pool**
68
- - Birth/life/death loop with a tick-based simulation (e.g., one tick = one year)
69
- - Shared resource pool with scarcity/abundance knobs
70
- - Karma accumulation and rebirth mapping
71
- - Metrics + simple charts
72
-
73
- ### Phase 2 — Social interactions
74
- - Friendship/partnering rules
75
- - Cooperation/conflict mechanics
76
- - Network effects (who influences whom)
77
- - New metrics: cohesion, inequality, conflict rate, cluster formation
78
-
79
- ### Phase 3 — Identity + norms
80
- - Race/faith labels and trust matrices
81
- - “Beauty” norms as socially defined advantage/disadvantage
82
- - Bias and discrimination parameters
83
-
84
- ### Phase 4 — Rich events + scenario comparison UX
85
- - Expanded event catalogue and world shocks
86
- - Side-by-side scenario runner (good-biased vs bad-biased, scarcity vs abundance)
87
- - Saved runs, replay, and comparative dashboards
88
-
89
- ### Phase 5 — Philosophical schools as pluggable worldviews
90
- - Define a `Worldview` interface (policy + karma + rebirth + liberation hooks)
91
- - Implement first set of worldview modules (Advaita, Vishishtadvaita, Buddhist lens)
92
- - Add scenario comparison: same seed/config, different worldview → compare metrics and liberation rates
93
- - Add new metrics relevant to worldviews (e.g., attachment/craving proxy, compassion proxy, “liberation” events)
94
-
95
- ## V1 technical plan (build the minimum interesting world)
96
- V1 is the smallest version that can answer: **does “good vs bad bias” + “scarcity vs abundance” meaningfully change world-level outcomes over generations?**
97
-
98
- ### Deliverable (what “done” looks like for V1)
99
- - A single command starts an interactive app where you can:
100
- - set parameters (seed, population size, resource abundance, bias toward good/bad nature)
101
- - run for `N` ticks / generations
102
- - view metrics and charts
103
- - Runs are reproducible via seed + config snapshot.
104
-
105
- ### Running (Windows / PowerShell)
106
- From `c:\Workspace\agentic-ai\projects\god`:
107
-
108
- - Run the CLI (prints JSON):
109
-
110
- ```bash
111
- uv sync
112
- uv run god-sim --ticks 200 --num-souls 300
113
- ```
114
-
115
- - Run the UI (Streamlit):
116
-
117
- ```bash
118
- uv sync
119
- uv run streamlit run .\src\god_sim\app\streamlit_app.py
120
- ```
121
-
122
- ### Run history persistence
123
- - Every simulation run is automatically saved to `data/run_history.json`.
124
- - Each record contains:
125
- - `run_id`, `created_at_utc`
126
- - `config`
127
- - `final` metrics snapshot
128
- - full `series` time-series data
129
- - The dashboard includes a **Run History** section to compare recent runs.
130
-
131
- ### Local LLM insights (Gemma via Ollama)
132
- The UI can optionally ask a **local** model to summarize and interpret a run (no cloud required).
133
-
134
- 1) Install and start Ollama, then pull a small Gemma model (example):
135
 
136
  ```bash
137
- ollama pull gemma2:2b
138
- ollama serve
139
  ```
140
 
141
- 2) Run the app and click **Generate insights from last run**.
142
-
143
- 3) Optional environment variables:
144
- - `GOD_LLM_PROVIDER`: `ollama` (default) or `openai_compatible`
145
- - `OLLAMA_BASE_URL`: default `http://localhost:11434`
146
- - `OLLAMA_MODEL`: default `gemma2:2b`
147
- - `OPENAI_BASE_URL`: default `http://localhost:1234/v1` (for local OpenAI-compatible servers)
148
- - `OPENAI_MODEL`: default `gemma`
149
- - `OPENAI_API_KEY`: only if your local server requires it
150
-
151
- ### Fully offline LLM insights (no server) using your HF `.bin`
152
- Your Hugging Face repo contains a local file `gemma-2b-it-cpu-int4.bin` (uploaded here: [`vikramvasudevan/gemma-for-panchangam`](https://huggingface.co/vikramvasudevan/gemma-for-panchangam)).
153
-
154
- Important format note:
155
- - `llama-cpp-python` expects **GGUF** files for `provider=llama_cpp`.
156
- - A `.bin` file may download successfully but still fail to load in `llama_cpp`.
157
- - If you want to use your current `.bin`, use `provider=ollama` (server mode), or obtain/convert a GGUF model for fully offline `llama_cpp`.
158
-
159
- 1) Download the model file into `.\models\`:
160
-
161
- ```bash
162
- uv sync
163
- uv run god-sim-download-model --repo vikramvasudevan/gemma-for-panchangam --file gemma-2b-it-cpu-int4.bin --out models
164
- ```
165
-
166
- 2) Run the UI and choose provider `llama_cpp` in the Insights section, or set env vars:
167
- - `GOD_LLM_PROVIDER=llama_cpp`
168
- - `GOD_LLM_MODEL_PATH=models/<your-model>.gguf`
169
- - (optional) `GOD_LLM_N_CTX=4096`, `GOD_LLM_N_THREADS=0`
170
-
171
- If the model path is missing, the app now tries to **auto-download** from Hugging Face by default.
172
-
173
- Optional controls:
174
- - `GOD_LLM_AUTO_DOWNLOAD=1` (default) or `0`
175
- - `GOD_LLM_HF_REPO=vikramvasudevan/gemma-for-panchangam`
176
- - `GOD_LLM_HF_FILE=gemma-2b-it-cpu-int4.bin`
177
-
178
- ### Recommended stack
179
- - **Python**: `dataclasses` + type hints
180
- - **Numerics**: `numpy` (optionally `pandas` if it helps)
181
- - **Visualization/UI**: **Streamlit** (fastest to iterate on “play God” sliders + charts)
182
- - **Plots**: `plotly` (or `matplotlib`)
183
-
184
- ### Suggested code organization
185
- ```
186
- god/
187
- README.md
188
- pyproject.toml
189
- main.py # CLI or entrypoint (later can launch Streamlit)
190
- src/god_sim/
191
- __init__.py
192
- config.py # WorldConfig, scenario presets
193
- domain/
194
- soul.py # Soul (id, karma)
195
- person.py # Person (traits, identity, wellbeing, relationships)
196
- world.py # World state (population, resources, time)
197
- resources.py # ResourcePool (replenish, consume)
198
- events.py # Event types and effects
199
- engine/
200
- sim.py # run_simulation(), step_world()
201
- rebirth.py # Rebirth rules (karma → next-life initialization)
202
- karma.py # Karma updates from actions/outcomes
203
- rules/
204
- decisions.py # cooperate/hoard/help/harm policy driven by moral_bias
205
- social.py # (minimal in V1) optional basic interaction
206
- analytics/
207
- metrics.py # collectors + aggregations
208
- report.py # plot helpers
209
- app/
210
- streamlit_app.py # sliders → run → charts
211
- ```
212
-
213
- ### Core data model (V1)
214
- Start numeric and simple; keep everything observable.
215
-
216
- - `Soul`
217
- - `soul_id: int`
218
- - `karma: float`
219
-
220
- - `Person`
221
- - `soul_id: int`
222
- - `age: int`
223
- - `max_age: int` (sampled)
224
- - `health: float`
225
- - `wellbeing: float`
226
- - `moral_bias: float` (good↔bad)
227
- - `consumption_need: float`
228
- - (optional in V1) `race`, `faith`, `beauty_score` (can exist but not heavily used yet)
229
-
230
- - `World`
231
- - `time: int`
232
- - `resource_pool: ResourcePool`
233
- - `people: list[Person]`
234
- - `souls: dict[int, Soul]`
235
-
236
- ### Simulation loop (tick-based)
237
- For each tick:
238
- - Replenish global resources
239
- - For each person:
240
- - consume resources (if insufficient, wellbeing/health drop)
241
- - decide actions influenced by `moral_bias` (e.g., share vs hoard)
242
- - sample an event (configurable probabilities)
243
- - update wellbeing/health/karma
244
- - Age everyone, apply deaths
245
- - For each death:
246
- - update soul karma summary if needed
247
- - rebirth: create a new `Person` for the same `Soul`, with traits drawn from distributions shifted by karma
248
- - Collect metrics for this tick
249
-
250
- ### Metrics to track in V1 (minimum set)
251
- - Population alive over time (should remain stable-ish given constant soul pool, but death/birth timing matters)
252
- - Mean/median karma and distribution (histogram)
253
- - Mean/median wellbeing and distribution
254
- - Resource pool level over time
255
- - Inequality proxy (simple: Gini of wellbeing or resources consumed; can be added later)
256
- - Event counts by type
257
-
258
- ### Scenario knobs (V1 controls)
259
- - `seed`
260
- - `num_souls`
261
- - `ticks`
262
- - `resource_replenish_rate`
263
- - `resource_capacity`
264
- - `baseline_consumption_need`
265
- - `event_rate` and event mix
266
- - `initial_moral_bias_mean` and `initial_moral_bias_std`
267
- - `rebirth_influence_strength` (how strongly karma affects next-life traits)
268
-
269
- ### Testing/validation (pragmatic)
270
- - Same config + seed produces the same metrics time series
271
- - Extreme scenarios behave sensibly:
272
- - very low replenish rate → widespread suffering / collapse-like signals
273
- - high replenish rate + good bias → higher wellbeing and lower conflict proxies (even if conflict is minimal in V1)
274
-
275
- ---
276
 
277
- ### Notes
278
- - The original project statement is preserved as `README.backup.md` in this folder.
 
 
 
 
 
19
  - **Bias experiments**: What happens to world stability when the population is biased toward “good nature” vs “bad nature”?
20
  - **Scarcity vs abundance**: How do shared natural resources shape inequality, wellbeing, cooperation/conflict, and longevity?
21
  - **Identity dynamics**: How do race/faith/beauty norms influence social networks and opportunity, and how do they compound over rebirth cycles?
22
+ - **Sustainability Equilibrium**: What is the ideal balance of population, resources, and moral bias to ensure world longevity?
 
23
 
24
+ ### Core Features
25
+ - **Deterministic Simulation**: Tick-based engine where every run is reproducible via seed.
26
+ - **Sustainable Equilibrium Optimizer**: An auto-tuning tool that hunts for parameters that maximize world longevity (surviving collapse).
27
+ - **Run History & AI Comparison**: Automatically saves all runs and allows AI to generate comparative insights between two different worlds.
28
+ - **Local AI Insights**: Uses Gemma 2 2b (via `llama_cpp` or `Ollama`) to quantitatively interpret simulation results and causal links.
29
 
30
+ ### High-level model
31
  - **Soul**: immutable id; persists across lifetimes; carries karma forward.
32
+ - **Person**: a transient body with traits (moral bias, health, wellbeing).
33
+ - **Karma**: numeric score updated by actions; influences next-life initialization.
34
+ - **Resources**: global pool with replenishment; consumption influenced by moral bias (sharing vs hoarding).
35
+ - **World Collapse**: Simulation ends if resources hit 0, everyone dies, or karma reaches 0.
 
 
 
36
 
37
+ ### Running the App
38
+ The app is optimized for Hugging Face Spaces using Docker, but can be run locally:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  ```bash
41
+ # Run the UI (Streamlit)
42
+ uv run streamlit run src/god_sim/app/streamlit_app.py
43
  ```
44
 
45
+ ### Local LLM insights
46
+ 1) Install Ollama and pull Gemma: `ollama pull gemma2:2b`
47
+ 2) Run the app and click **Generate insights**.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
+ ### Hugging Face Deployment
50
+ The app uses `llama_cpp` with GGUF for fast, serverless insights:
51
+ - **Provider**: `llama_cpp`
52
+ - **Model Repo**: `bartowski/gemma-2-2b-it-GGUF`
53
+ - **Model File**: `gemma-2-2b-it-Q4_K_M.gguf`
54
+ - **Context Window**: 8192 tokens.
SKILLS.md CHANGED
@@ -1,68 +1,33 @@
1
  # GOD Simulation Skills & Knowledge
2
 
3
- This document serves as a guide for working on the GOD reincarnation-based social simulation. It outlines the core mental models, technical patterns, and workflows used in this project.
4
 
5
  ## 核心理念 (Core Philosophy)
6
  The project is a "world engine" simulating a fixed pool of souls cycling through birth, life, death, and rebirth.
7
  - **Fixed Soul Pool:** Souls are persistent; only their physical manifestations (Persons) cycle.
8
- - **Karma-Driven Rebirth:** Actions in one life influence the starting conditions of the next.
9
- - **Resource Scarcity:** A central driver for behavior (cooperation vs. hoarding).
10
- - **Extensible Worldviews:** (Planned) Pluggable rulesets for different philosophical lenses (Advaita, Buddhist, etc.).
11
 
12
- ## Domain Models (`src/god_sim/domain/`)
13
- - **`Soul`**: Immutable ID + persistent `karma`. Carries history across lifetimes.
14
- - **`Person`**: The transient physical entity. Has `age`, `health`, `wellbeing`, `moral_bias`, and `consumption_need`.
15
- - **`World`**: Container for the `ResourcePool`, `Person` list, and `Soul` dictionary.
16
- - **`ResourcePool`**: Manages finite resources with a replenishment rate.
17
 
18
- ## Simulation Engine (`src/god_sim/engine/sim.py`)
19
- - **Tick-Based:** The simulation progresses in discrete time steps (ticks).
20
- - **Step Logic:**
21
- 1. **Replenish Resources:** Global pool grows by `replenish_rate`.
22
- 2. **Consumption & Interaction:**
23
- - High `moral_bias` (good) -> Sharing part of resources.
24
- - Low `moral_bias` (bad) -> Hoarding (requesting more than need).
25
- - Shortfalls hurt health/wellbeing; surplus helps.
26
- 3. **Karma Updates:** Updated based on `moral_bias` and life events.
27
- 4. **Events:** Stochastic shocks (positive/negative) impacting health/wellbeing.
28
- 5. **Aging & Death:** Health drops with age; death triggers rebirth.
29
- 6. **Rebirth:** A new `Person` is created for the `Soul`. Karma influences the new `moral_bias`.
30
 
31
- ## Analytics & Metrics (`src/god_sim/analytics/`)
32
- - Every tick produces a metric snapshot: `alive`, `resource`, `mean_karma`, `mean_wellbeing`, `mean_health`, `events`.
33
- - **Persistence:** Runs are saved to `data/run_history.json` for comparison.
34
 
35
- ## AI Insights (`src/god_sim/insights/`)
36
- The system uses LLMs to interpret simulation results.
37
- - **Providers:** Supports `ollama` (local dev), `openai_compatible`, and `llama_cpp` (recommended for Hugging Face).
38
- - **Format Note:** `llama_cpp` requires **GGUF** files. Old `.bin` files will not work.
39
- - **Recommended for HF Spaces:**
40
- - `GOD_LLM_PROVIDER`: `llama_cpp`
41
- - `GOD_LLM_HF_REPO`: `bartowski/gemma-2-2b-it-GGUF`
42
- - `GOD_LLM_HF_FILE`: `gemma-2-2b-it-Q4_K_M.gguf`
43
- - **Workflow:**
44
- 1. `build_run_summary` extracts deltas and trends from the simulation output.
45
- 2. LLM analyzes JSON summary to provide bulleted insights and suggested experiments.
46
 
47
- ## Development Workflows
48
-
49
- ### Running the CLI
50
- ```bash
51
- uv run god-sim --ticks 200 --num-souls 300
52
- ```
53
-
54
- ### Running the Dashboard
55
- ```bash
56
- uv run streamlit run src/god_sim/app/streamlit_app.py
57
- ```
58
 
59
- ### Key Configurations (`src/god_sim/config.py`)
60
- Modify `WorldConfig` to tune the simulation:
61
- - `initial_moral_bias_mean/std`: Sets the world's starting "nature".
62
- - `resource_replenish_rate`: Controls scarcity.
63
- - `rebirth_influence_strength`: Controls how much karma matters for the next life.
64
-
65
- ## Adding New Features
66
- - **New Metrics:** Update `step_world` return dict and `analytics/metrics.py`.
67
- - **New Rules:** Add logic to `step_world` or create a new module in `rules/`.
68
- - **New Worldviews:** Implement hooks in `engine/sim.py` that change `moral_bias` interpretation or karma calculation.
 
1
  # GOD Simulation Skills & Knowledge
2
 
3
+ This document serves as a guide for working on the GOD reincarnation-based social simulation.
4
 
5
  ## 核心理念 (Core Philosophy)
6
  The project is a "world engine" simulating a fixed pool of souls cycling through birth, life, death, and rebirth.
7
  - **Fixed Soul Pool:** Souls are persistent; only their physical manifestations (Persons) cycle.
8
+ - **Sustainability Equilibrium:** The goal is to find parameters where the world does not collapse.
9
+ - **Collapse Conditions:** Resources = 0, Population = 0, or Karma = 0.
 
10
 
11
+ ## Simulation Engine (`src/god_sim/engine/`)
 
 
 
 
12
 
13
+ ### Core Simulator (`sim.py`)
14
+ - **Step Logic:** Replenish -> Consume/Interact -> Update Karma -> Events -> Age/Death -> Rebirth.
15
+ - **Collapsed Flag:** Every tick checks if the world has met any exit conditions.
 
 
 
 
 
 
 
 
 
16
 
17
+ ### Sustainable Equilibrium Optimizer (`optimizer.py`)
18
+ - **Evaluation**: Uses a fitness function based on "Longevity" (ticks survived).
19
+ - **Random Search**: Iterates through parameter combinations to find the highest fitness world configuration for a fixed resource capacity.
20
 
21
+ ## AI Insights & Comparisons (`src/god_sim/insights/`)
22
+ The system uses LLMs (Gemma 2 2b) to interpret results.
23
+ - **Single Run (`generate_insights`)**: Quantitative analysis of deltas and trends.
24
+ - **Comparative (`generate_comparative_insights`)**: Analyzing two runs to find causal links between parameter changes and outcomes.
25
+ - **Local Deployment**: Uses `llama_cpp` with GGUF files and an 8192 context window.
 
 
 
 
 
 
26
 
27
+ ## Analytics & Persistence (`src/god_sim/analytics/`)
28
+ - **JSON Serialization**: Uses a custom `SimulationEncoder` in `history.py` to handle `numpy` types and booleans.
29
+ - **Run History**: Saved to `data/run_history.json`.
 
 
 
 
 
 
 
 
30
 
31
+ ## Development Workflows
32
+ - **Hugging Face**: Deployed via Docker. Environment variables `GOD_LLM_PROVIDER`, `GOD_LLM_HF_REPO`, and `GOD_LLM_HF_FILE` control the AI engine.
33
+ - **Streamlit**: Main entry point is `src/god_sim/app/streamlit_app.py`.
 
 
 
 
 
 
 
src/god_sim/app/streamlit_app.py CHANGED
@@ -218,6 +218,30 @@ if history:
218
  }
219
  )
220
  st.dataframe(pd.DataFrame(rows), width="stretch")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  else:
222
  st.caption("No runs stored yet. Run a simulation to create history.")
223
 
 
218
  }
219
  )
220
  st.dataframe(pd.DataFrame(rows), width="stretch")
221
+
222
+ st.subheader("⚖️ AI Comparison")
223
+ st.caption("Select two runs from history to compare them using AI.")
224
+ compare_runs = st.multiselect(
225
+ "Select exactly 2 runs",
226
+ options=list(run_options.keys()),
227
+ max_selections=2,
228
+ help="Select two runs to see how their parameters influenced the emergent world outcomes."
229
+ )
230
+
231
+ if len(compare_runs) == 2:
232
+ if st.button("Generate Comparative Insights"):
233
+ from god_sim.insights.llm import generate_comparative_insights
234
+ run_a = run_options[compare_runs[0]]
235
+ run_b = run_options[compare_runs[1]]
236
+
237
+ cfg_ins = insight_config_from_env()
238
+ # (Assuming standard provider/model selection from below or env)
239
+ try:
240
+ with st.spinner("Analyzing differences..."):
241
+ comparison_text = generate_comparative_insights(run_a, run_b, cfg=cfg_ins)
242
+ st.markdown(comparison_text)
243
+ except Exception as e:
244
+ st.error(f"Comparison failed: {e}")
245
  else:
246
  st.caption("No runs stored yet. Run a simulation to create history.")
247
 
src/god_sim/insights/llm.py CHANGED
@@ -236,3 +236,61 @@ def generate_insights(sim_output: dict[str, Any], cfg: InsightConfig | None = No
236
  data = r.json()
237
  return str(data["choices"][0]["message"]["content"]).strip()
238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  data = r.json()
237
  return str(data["choices"][0]["message"]["content"]).strip()
238
 
239
+ def generate_comparative_insights(out_a: dict[str, Any], out_b: dict[str, Any], cfg: InsightConfig | None = None, timeout_s: int = 120) -> str:
240
+ cfg = cfg or insight_config_from_env()
241
+ summary_a = build_run_summary(out_a, df_tail_rows=10)
242
+ summary_b = build_run_summary(out_b, df_tail_rows=10)
243
+
244
+ user_prompt = (
245
+ "Compare these TWO simulation runs (A and B).\n\n"
246
+ f"RUN_A_SUMMARY:\n{json.dumps(summary_a, indent=2)}\n\n"
247
+ f"RUN_B_SUMMARY:\n{json.dumps(summary_b, indent=2)}\n\n"
248
+ "Analyze the impact of the parameter differences on the outcomes.\n"
249
+ "Return:\n"
250
+ "1) Key differences in longevity and stability\n"
251
+ "2) Causal link: which parameter change likely caused the most significant divergence?\n"
252
+ "3) Which world was 'healthier' and why?\n"
253
+ )
254
+
255
+ if cfg.provider == "ollama":
256
+ url = cfg.ollama_base_url.rstrip("/") + "/api/generate"
257
+ payload = {
258
+ "model": cfg.ollama_model,
259
+ "prompt": user_prompt,
260
+ "system": "You are a comparative analyst for world simulations. Focus on causal differences.",
261
+ "stream": False,
262
+ "options": {"temperature": cfg.temperature},
263
+ }
264
+ r = requests.post(url, json=payload, timeout=timeout_s)
265
+ r.raise_for_status()
266
+ return str(r.json().get("response", "")).strip()
267
+
268
+ if cfg.provider == "llama_cpp":
269
+ try:
270
+ from llama_cpp import Llama
271
+ except ImportError:
272
+ raise RuntimeError("llama-cpp-python not available.")
273
+
274
+ model_path = Path(cfg.model_path)
275
+ llm = Llama(model_path=str(model_path), n_ctx=cfg.n_ctx, n_threads=None if cfg.n_threads <= 0 else cfg.n_threads, verbose=False)
276
+ prompt = f"System: You are a comparative analyst.\nUser: {user_prompt}"
277
+ out = llm(prompt, max_tokens=cfg.max_tokens, temperature=cfg.temperature, stop=["</s>"])
278
+ return str(out["choices"][0]["text"]).strip()
279
+
280
+ # OpenAI-compatible
281
+ url = cfg.openai_base_url.rstrip("/") + "/chat/completions"
282
+ headers = {"Content-Type": "application/json"}
283
+ if cfg.openai_api_key:
284
+ headers["Authorization"] = f"Bearer {cfg.openai_api_key}"
285
+ payload = {
286
+ "model": cfg.openai_model,
287
+ "temperature": cfg.temperature,
288
+ "max_tokens": cfg.max_tokens,
289
+ "messages": [
290
+ {"role": "system", "content": "You are a comparative analyst."},
291
+ {"role": "user", "content": user_prompt},
292
+ ],
293
+ }
294
+ r = requests.post(url, headers=headers, json=payload, timeout=timeout_s)
295
+ r.raise_for_status()
296
+ return str(r.json()["choices"][0]["message"]["content"]).strip()