- Three.js isometric 3D city with 70 locations: houses, apartments, shops,
offices, factories, public buildings (police, fire, museum, mall, townhall,
market), parks, and entertainment venues
- Detailed humanoid figures with arms, legs, clothing, walking animation
- Sky system: sun/moon, stars, clouds, mountains, day/night lighting
- 75 demo agents with collision avoidance around buildings
- Grid of streets connecting all city blocks
- /3d route added to FastAPI server
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Major simulation features:
- Age progression (1 year per 365 sim days) with lifecycle stages
- Death system for 80+ with exponential probability curve
- Divorce mechanic for unhappy marriages (low trust/sentiment/mood)
- Married couples move in together (cohabitation)
- Church wedding ceremonies, hospital births after 9 sim-day pregnancy
- Baby agents born as real citizens, living with parents, autonomous at age 4
- Annual mayor elections with weighted voting (18+ citizens)
- Short-term (weekly) and long-term goals with auto-refresh
- Memory query API: ask any agent about their memories via LLM
- Community score tracking for election candidacy
- UI: lifecycle badges, deceased agents, mayor display, split goals,
memory query input, parent info, new event icons
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
NN training: realistic persona data, graphs, hot-reload endpointβ
- Update all 20 personas in nn_train.py and nn_selfimprove.py to match
enhanced personas.yaml (corrected names, ages, traits, occupations)
- Add persona-specific behavioral patterns: night shift schedule (George),
nightly bar routine (Frank), crush proximity (LilaβElena), taxi wandering
(Omar), overworked doctor (Priya), morning exercise (Marcus/Yuki), etc.
- Add persona-aware needs generation, mood calculation, starting locations
- Add training graph plots (loss + accuracy curves) after training
- Add --graph flag to display graphs from last training run
- Decouple --push from training (push existing model without retraining)
- Add POST /api/nn/reload endpoint for hot-reloading ONNX model from HF Hub
- NNClient.reload() deletes cache, re-downloads, swaps ONNX session in-place
- Both scripts auto-trigger /api/nn/reload after pushing to HF Hub
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix StockEx order endpoint: use shared database helperβ
Was creating a new Database() instance which crashes. Now uses
_get_player_from_token() like all other player endpoints.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add StockEx trading integration for player agentsβ
- New API endpoints: /stockex/market, /stockex/leaderboard,
/stockex/portfolio/{id}, /stockex/order
- Player agents can browse market data, view portfolios, and place
buy/sell orders on StockEx clearing house
- Orders recorded as life events and memories for the agent
- Web UI: StockEx button in player panel opens trading modal with
live market data, portfolio view, and order form
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add life events, goals, pregnancy system; fix profile editor bugsβ
- Life events: append-only timeline seeded from persona, extended by
LLM reflections and romance milestones (dating/engaged/married/birth)
- Goals: personal aspirations with progress tracking, managed by LLM
reflections (add/complete/progress)
- Pregnancy: married couples can conceive, birth after ~7 sim-days,
baby names, both parents get memories and life events
- Agent context: LLM now sees life story, goals, children, pregnancy
- Fix profile editor: fetch full agent detail instead of WS summary
(occupation, background, personality sliders now load correctly)
- Fix Go dropdown: only rebuild when empty, preserves user selection
- Fix WS state summary: include age, occupation, daily_plan, is_player
- NN self-improve: track accuracy in training_stats.json, compare with
previous model on push
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Detect actual quota exhaustion via llm_status (429 errors), not just
in-memory counter which resets on server restart
- NN auto-sets probability to 100% when selected
- Remove "local" from NN label
- Popup probability slider initializes from current probability, not hardcoded 20%
- Fix pqForCalc to include rpm field for accurate runtime estimates
- Quota badge shows "exhausted" when API is actually rate-limited
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix quota runtime estimates: use RPM as bottleneck, sync top probability sliderβ
- Runtime estimate now based on RPM (Gemini 4 RPM = 240 calls/h, ~6.25h for 1500 RPD)
not probability, which barely affects duration with 50 agents
- Remove misleading per-probability runtime table from popup
- Show RPM and single accurate runtime estimate instead
- Fix ID collision between top slider and popup slider (use class selectors)
- Sync top probability slider when switching provider via popup
- Expose RPM and max_calls_per_hour in /api/llm/quota per-provider data
- Update nn_selfimprove budget calculations to use RPM-based math
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix quota endpoint: per-provider tick rates for accurate runtime estimatesβ
- Add GET /api/llm/quota endpoint exposing per-provider daily quota (Gemini 1500 RPD, Groq 14400 RPD)
- Add personality/home/work fields to agent detail API for NN training data collection
- Fix nn_selfimprove: /api/agents returns dict not list, correct probability endpoint path
- Fix Gemini scheduled reset to 10:00 AM Athens instead of midnight
- Add 'budget' CLI mode to calculate and apply optimal probability for target duration
- Scheduled mode now auto-calculates probability from remaining quota
- Frontend: rate-limited providers (Gemini/Groq) show quota badge and expand a panel
with runtime estimates table, probability slider, and confirm button before switching
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diversify agent activities, add local training script, scheduled Gemini cycle, architecture diagramβ
- routine.py: Add morning/post-work exercise, park lunch, sports_field for more
personality types, varied activity descriptions, park as exercise destination
- nn_train.py: Standalone local training script (equivalent to Kaggle notebook)
with synthetic data gen, ONNX export, HF push, CUDA support
- nn_selfimprove.py: Add 'scheduled' mode for nightly Gemini collection + retrain,
oversample LLM-sourced samples 3x during training
- routes.py: Fix valid providers list (nn instead of hf)
- docs/architecture.html: SVG diagram of SociAgentTransformer architecture
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add NN provider as default, remove HF inference (7B/0.5B)β
- New NNClient: downloads ONNX model from RayMelius/soci-agent-nn on
first use, runs inference via onnxruntime on CPU (~1ms for 50 agents).
Zero API calls, zero cost, works offline.
- NN is now the default provider β always available, no API key needed.
LLM probability defaults to 100% for NN (no rate limiting).
- Removed HFInferenceClient and all 7B/0.5B model references β these
required HF Pro credits and never worked on free tier.
- Updated provider list in UI, fallback order, and provider icons.
- Added training notebook (notebooks/soci_agent_nn.ipynb).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Stop persisting LLM probability to DB and default endpoint to 0.10β
The DB-saved probability was overriding the provider default on restarts.
Also changed the endpoint default from 1.0 to 0.10 to match the intended
behavior for cloud providers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Default LLM probability to 10% for cloud providers, ignore stale DB valueβ
The DB-saved slider value (often 1.0 from local Ollama sessions) was
overriding the provider default on HF deploys, causing Gemini to burn
through its daily quota in minutes. Now always starts with the provider
default (10% for cloud, 100% for Ollama) β users can still adjust via
the UI slider during the session.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix Gemini conversations: bump LLM budget to 2 and remove double probability gateβ
With budget=1, action decisions consumed the entire per-tick allowance,
leaving zero budget for conversations. Also, active conversations were
gated by llm_call_probability on every turn β now they always continue
once started.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reset Gemini circuit breaker after failed startup probeβ
A single 429 on the probe was circuit-breaking for the entire day,
leaving the simulation in routine-only mode. Now the breaker resets
so the sim loop can retry gracefully per-tick.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add logging config so server output is visible in HF container logsβ
soci-agent-7b and soci-agent-q4 are public repos β always show them
regardless of whether HF_TOKEN is set (e.g. on Render).
Other HF models still gated behind HF_TOKEN.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clean up LLM selector: only deployed HF models, remove Ollama soci variantsβ
- HF soci entries: keep only deployed models (7b, q4); drop 8b/3b/1b5 (not on HF)
- Ollama: remove all soci-agent variants (Ollama unreachable on HF Space)
- Keep generic Ollama (local) entry for local deployments
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add all soci-agent model variants to LLM selectorβ
- HF provider now defaults to RayMelius/soci-agent-q4 (was SmolLM3)
- Ollama provider now defaults to soci-agent (was llama3.1:8b)
- Startup priority: Claude > HF/soci-agent > Groq > Gemini > Ollama
- auto-detect order in create_llm_client matches new priority
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add Soci fine-tuned model and training data pipelineβ
- Add RayMelius/soci-agent-q4 (fine-tuned Qwen2.5-0.5B) to HF provider list
- Add soci-agent as named Ollama option for GGUF-loaded model
- Add MODEL_HF_SOCI and MODEL_OLLAMA_SOCI constants to llm.py
- Persist conversation_history in simulation snapshots (to_dict/from_dict)
- scripts/collect_training_data.py: poll Render API, save raw JSONL
- scripts/convert_to_training_jsonl.py: convert to SFT chat format
- scripts/finetune_local.py: local Unsloth fine-tune (RTX 4050, Windows-safe)
Fixes: transformers 4.56 list_repo_templates patch, TORCHINDUCTOR_DISABLE
Round 1: 116 examples, 3 epochs, loss 1.9222, LoRA -> RayMelius/soci-agent-q4
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix NameError: import PROVIDER_OLLAMA and PROVIDER_CLAUDE in server.pyβ
Prevents hitting daily quotas quickly. Users can raise via the slider
or SOCI_LLM_PROB env var. At 10%: ~15 calls/h on Gemini free tier.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Auto-fallback provider on startup if configured provider is quota-exhaustedβ
On startup, probe the chosen provider with a minimal LLM call. If it fails
(quota exhausted, model unavailable, etc.), try Groq β Gemini β Ollama in
order until one works. This prevents the sim from starting in broken state
when e.g. SOCI_PROVIDER=gemini but the daily quota was already used up.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix Gemini default: use gemini-2.0-flash-lite (confirmed free-tier working)β
Live testing showed:
- gemini-1.5-flash* models β 404 on current API keys (deprecated/unavailable)
- gemini-2.0-flash-lite β reaches API, only fails when daily quota exhausted
- gemini-2.0-flash-001 β same (valid model, quota-limited)
Update default to gemini-2.0-flash-lite, fallback chain to 2.x models only,
and fix provider label in UI. Switch live Space to Groq (working now).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix HF provider: require token, hide from menu if absent, fix stuck providerβ
- HFInferenceClient.__init__ now raises ValueError if no token found
(checks HF_TOKEN, HUGGINGFACE_TOKEN, HF_API_TOKEN); prevents silently
creating a broken client that gets stuck as active provider
- /llm/providers: HF models only shown when token is available
- /llm/provider: ValueError from missing credentials returns 400 not 500
- Fix Gemini label: "1.5 Flash" (matches actual default model)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Persist LLM probability across restarts; fix Gemini model fallbackβ
- Add `settings` table to SQLite DB for key-value config persistence
- On startup: load saved llm_call_probability from DB (env var still wins);
env var value is also written back so other workstations inherit it
- On slider change: persist new value to DB immediately
- GeminiClient: auto-fallback to gemini-1.5-flash when configured model
returns 400/404 "not found" on the serverless endpoint; tracks unavailable
models per-instance so future calls skip straight to fallback
- Add _GEMINI_FALLBACK_CHAIN and MODEL_GEMINI_FLASH_FALLBACK constants
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add LLM probability slider: controls AI usage per call siteβ
Adds a 0-100% slider (brain emoji, in the toolbar between speed and
zoom controls) that gates every LLM call in the simulation:
- Action decisions, conversation turns, reflections, social starts,
daily plan generation β each rolls random() < llm_call_probability.
Provider defaults (tuned for free-tier daily quotas):
Gemini β 45% (4 RPM + budget=1 β ~150 calls/h β ~10h at 1500 RPD)
Groq β 70% (conserves daily token budget)
HF β 45%
Ollama/Claude β 100% (no quota)
Also reduces Gemini's _max_llm_calls_this_tick from 4 β 1 so the
rate limiter (15s/call) naturally paces the simulation without
needing to burn all 4 budget slots every tick.
Override default via SOCI_LLM_PROB env var (0.0β1.0).
API: GET /api/controls β llm_call_probability field
POST /api/controls/llm_probability?value=0.45
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Clean up token env vars; add Gemini to free provider menuβ
- HFInferenceClient: drop hf_soci_token / soci_token / HW_WR_TOKEN β
HF_TOKEN is the only supported var (auto-injected by HF Spaces)
- create_llm_client: same β only HF_TOKEN triggers HF auto-detection
- _choose_provider: show Groq + Gemini (both free-tier) before HF and Ollama;
remove has_claude (Claude never appeared in the menu anyway)
- HF now labelled "requires HF PRO / credits" to set correct expectations
- SOCI_PROVIDER / LLM_PROVIDER env var still overrides everything (can force
any provider including claude)
Tokens safe to delete from HF settings: soci_token, soci_read, hf_soci_token
SOCI_PROVIDER is not a secret β safe to use as a public Space variable
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remove paid providers from menu; circuit-break on 402 (no credits)β
- _choose_provider: offer only free providers (HF SmolLM3, Groq, Ollama);
Claude/Gemini can still be forced via SOCI_PROVIDER env var
- HFInferenceClient: add 402 to circuit-breaker (same as 401/403/410) so
the sim stops retrying when the token lacks Inference Providers permission
- Fix: add hf_soci_token Space secret with a personal HF token that has
Inference Providers (Write) permission to enable SmolLM3 for free
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix HF LLM: use free SmolLM3 as default, strip thinking tokensβ
The Qwen/7B model was causing 402 (credit balance depleted) because it
auto-routes to a paid third-party provider via the HF router.
SmolLM3-3B with :hf-inference runs on HF's own CPU cluster for free.
- Default model: HuggingFaceTB/SmolLM3-3B:hf-inference (no credits needed)
- Prepend /no_think to system prompts to disable SmolLM3 reasoning mode
- Strip <think>...</think> blocks from all HF responses as a safety net
- Add HW_WR_TOKEN to recognized env var names (Space write token)
- HW_WR_TOKEN / hf_soci_token now take priority over HF_TOKEN so a
personal token with credits overrides the Space's limited auto-token
- create_llm_client: detect HW_WR_TOKEN for HF auto-selection
- _choose_provider: detect HW_WR_TOKEN to offer HF in the menu
- Tested: complete() and complete_json() both work correctly with SmolLM3
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix HF Inference: migrate to router.huggingface.co/v1, use Qwen as defaultβ
- Update HFInferenceClient base_url to https://router.huggingface.co/v1/
(old hf-inference/ path returns 404 since the API was restructured in 2025)
- Change POST path from models/{id}/v1/chat/completions to chat/completions
- Replace defunct Zephyr-7b default with Qwen/Qwen2.5-7B-Instruct
(auto-routed by the HF router, produces coherent responses)
- Add MODEL_HF_SMOL as a no-credits fallback (hf-inference CPU provider)
- _map_model: fall back to model itself rather than default_model for unknown IDs
- _choose_provider: detect HF_TOKEN/hf_soci_token/soci_token and offer HF
as the first option (before Groq) so HF Spaces auto-selects it
- create_llm_client: also detect hf_soci_token/soci_token for auto-selection
- Tested: complete() returns 'Hello there!', complete_json() returns correct JSON
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix HF/Gemini LLM errors: token env var + rate limitingβ
- HFInferenceClient now reads soci_token as fallback to HF_TOKEN
- Set _last_error when no API key so test toast shows a useful message
- Include PROVIDER_GEMINI and PROVIDER_HF in is_rate_limited check so
the simulation loop caps LLM calls/tick (4 calls, 4s ticks) instead
of firing 10 concurrent requests and saturating the 15 RPM free tier
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Show actual HTTP error in LLM test toast instead of 'empty response'β
Track _last_error on every HF failure path (non-auth errors).
Test endpoint returns error field combining auth_error and last_error.
Toast now shows model name + real error e.g. 'HTTP 404: Model not found'
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Show all HF models individually in SWITCH LLM popupβ
- providers list now has 4 separate HF entries (Zephyr, Qwen, Llama, Mistral)
- SwitchProviderRequest accepts optional model field
- switch_llm_provider() forwards model to create_llm_client()
- /llm/providers returns current_model so UI can checkmark the right row
- active checkmark matches on both provider id + model
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Switch HF default model to zephyr-7b-beta (ungated, no license needed)β
Qwen/Qwen2.5-7B-Instruct had no visible license gate for the user.
HuggingFaceH4/zephyr-7b-beta is fully open with no access restrictions.
HF_MODEL env var can still override to any other model.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add LLM call counter, test button, and better HF error handlingβ
- LLM pill now shows ΓN call count each tick in green when active
- LLM popup has a π¬ Test button β makes a real call and shows raw response
- GET /api/llm/test endpoint for diagnosing provider issues
- HF 401/403 triggers circuit breaker + nokey status (gated model / bad token)
- HF 503 reads estimated_time from response body and waits accordingly
- auth_error field exposed on /llm/test for actionable diagnostics
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Show HF provider in switcher regardless of HF_TOKEN presenceβ
Like Ollama, HF is always listed β on HF Spaces the token is auto-injected,
and locally users just need to set HF_TOKEN once to use it.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add Hugging Face Serverless Inference as free LLM providerβ
- HFInferenceClient uses OpenAI-compatible endpoint at api-inference.huggingface.co
- Default model: Qwen2.5-7B-Instruct (also supports Llama-3.2-3B, Mistral-7B)
- HF_TOKEN auto-injected in HF Spaces β zero config needed on Spaces deployment
- Circuit breaker on quota exhaustion (same pattern as Groq/Gemini)
- Auto-detected in create_llm_client() when HF_TOKEN is set (after Gemini, before Ollama)
- Provider switcher UI shows π€ icon for hf provider
- routes.py and server.py updated to accept "hf" as a valid provider
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Split GITHUB_REPO into GITHUB_OWNER + GITHUB_REPO_NAME (no slash)β
Render and some other platforms reject '/' in env var values.
Code now reads GITHUB_OWNER + GITHUB_REPO_NAME and combines them;
falls back to the old GITHUB_REPO for any existing setups.
render.yaml updated to use the two-part variables.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Click model pill to switch LLM provider at runtimeβ
Backend:
- server.py: get_llm_provider() getter + switch_llm_provider() hot-swaps
sim.llm without restarting the simulation
- routes.py: GET /llm/providers returns available providers (those with
env keys set) + current; POST /llm/provider switches immediately
Frontend:
- #llm-model pill is now clickable (pointer cursor, hover highlight)
- Click opens a dark popup listing available providers with icons;
current provider shows a checkmark
- Selecting a different provider POSTs to the API and shows a toast;
clicking outside or re-clicking the pill closes the popup
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add render.yaml, fix gemini provider routing, show LLM model in headerβ
- render.yaml: declares LLM_PROVIDER=gemini as versioned config; secrets
(GEMINI_API_KEY, GROQ_API_KEY, etc.) listed as sync:false so they persist
from the Render dashboard without being stored in the repo
- server.py: _choose_provider() now accepts "gemini" from LLM_PROVIDER env var
- simulation.py: get_state_summary() includes llm_provider + llm_model fields
- index.html: header shows active model (e.g. β¦ 2.0-flash) with full name
as tooltip; icon varies by provider (β¦ gemini, β‘ groq, β claude, π¦ ollama)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix apartment assignment, player sleep, gender profile, and NPC conversationsβ
- Player now gets assigned to an available apartment block instead of town_square
- Players auto-sleep at home during sleeping hours (23:00-06:00) and auto-wake
- Added gender field (male/female/nonbinary) to player profile modal and API
- Gender-based attraction: only opposite genders (or nonbinary/unknown) develop romance
- Players now included in romance system (_tick_romance no longer skips is_player)
- Fixed NPC conversations: replaced is_busy check with conversable-state check
so agents eating/relaxing/working can still initiate conversations
- Doubled conversation base chance (extraversion/20 instead of /40)
- Raised max simultaneous conversations cap from 2 to 3
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
State is now saved to 'simulation-state' branch (not master), so GitHub
pushes never trigger Render auto-deploys. Also removed periodic 96-tick
GitHub push β only save on shutdown to minimise API calls.
- load_state_from_github: reads from simulation-state branch (?ref=)
- save_state_to_github: writes to simulation-state branch, auto-creates
branch from master on first save
- simulation_loop: removed periodic GitHub push (shutdown-only now)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Make startup crash-proof against corrupt/empty stateβ
- database.py: catch JSONDecodeError when loading snapshot from DB
- server.py: wrap load_simulation() in try/except β any error starts fresh
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Fix startup crash on empty/missing GitHub state fileβ