chore: initial commit

- Track MiroSociety source: backend (FastAPI), frontend (Vue3/Vite), docs, configs.
- Add start.sh / deploy.sh for local dev (uv venv + npm + dev servers on 31400/31401).
- Fix pyproject.toml: missing httpx dependency.
- Tighten .gitignore: .env, .venv, node_modules, data/, *.log, uv.lock, frontend/dist, etcd.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-09-17 13:48:30 +08:00
co-authored by Claude
commit 36b0f2b660
100 changed files with 26255 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
from app.models.world import (
Location,
TimeConfig,
WorldBlueprint,
WorldMetrics,
Institution,
Proposal,
WorldState,
)
from app.models.agent import Personality, AgentPersona
from app.models.action import ActionType, AgentDecision, ActionEntry, ReactiveResponse
from app.models.simulation import (
SimulationStatus,
SpeedMode,
SimulationState,
SSEEvent,
ForkRequest,
)
__all__ = [
"Location",
"TimeConfig",
"WorldBlueprint",
"WorldMetrics",
"Institution",
"Proposal",
"WorldState",
"Personality",
"AgentPersona",
"ActionType",
"AgentDecision",
"ActionEntry",
"ReactiveResponse",
"SimulationStatus",
"SpeedMode",
"SimulationState",
"SSEEvent",
"ForkRequest",
]
+64
View File
@@ -0,0 +1,64 @@
from __future__ import annotations
from enum import Enum
from typing import Literal
from pydantic import BaseModel, Field
class ActionType(str, Enum):
SPEAK_PUBLIC = "SPEAK_PUBLIC"
SPEAK_PRIVATE = "SPEAK_PRIVATE"
TRADE = "TRADE"
FORM_GROUP = "FORM_GROUP"
PROPOSE_RULE = "PROPOSE_RULE"
VOTE = "VOTE"
PROTEST = "PROTEST"
COMPLY = "COMPLY"
DEFECT = "DEFECT"
BUILD = "BUILD"
OBSERVE = "OBSERVE"
RECOMMEND = "RECOMMEND"
PURCHASE = "PURCHASE"
ABANDON = "ABANDON"
COMPARE = "COMPARE"
RESEARCH = "RESEARCH"
INVESTIGATE = "INVESTIGATE"
DO_NOTHING = "DO_NOTHING"
class AgentDecision(BaseModel):
feel: str = ""
want: str = ""
fear: str = ""
life_context: str = ""
past_echo: str = ""
action: ActionType = ActionType.DO_NOTHING
args: dict = Field(default_factory=dict)
speech: str | None = None
internal_thought: str = ""
belief_updates: list[str] = Field(default_factory=list)
memory_promotion: str | None = None
class ActionEntry(BaseModel):
round: int
day: int
time_of_day: str
agent_id: int
agent_name: str
location: str
action_type: ActionType
action_args: dict = Field(default_factory=dict)
speech: str | None = None
internal_thought: str | None = None
targets: list[int] = Field(default_factory=list)
world_state_changes: dict = Field(default_factory=dict)
relationship_changes: dict = Field(default_factory=dict)
class ReactiveResponse(BaseModel):
agent_id: int
agent_name: str = ""
reaction_type: Literal["respond", "whisper", "silent"] = "silent"
content: str | None = None
target_id: int | None = None
location: str = ""
+91
View File
@@ -0,0 +1,91 @@
from __future__ import annotations
from pydantic import BaseModel, Field
class SocialEdge(BaseModel):
target_id: int
strength: float = Field(default=0.5, ge=0.0, le=1.0)
sentiment: float = Field(default=0.0, ge=-1.0, le=1.0)
class Personality(BaseModel):
honesty: float = Field(default=0.5, ge=0.0, le=1.0)
ambition: float = Field(default=0.5, ge=0.0, le=1.0)
empathy: float = Field(default=0.5, ge=0.0, le=1.0)
confrontational: float = Field(default=0.5, ge=0.0, le=1.0)
conformity: float = Field(default=0.5, ge=0.0, le=1.0)
brand_loyalty: float = Field(default=0.5, ge=0.0, le=1.0)
price_sensitivity: float = Field(default=0.5, ge=0.0, le=1.0)
social_proof: float = Field(default=0.5, ge=0.0, le=1.0)
novelty_seeking: float = Field(default=0.5, ge=0.0, le=1.0)
COMMUNICATION_STYLES = {
"terse": "You speak in short, blunt sentences. 5-10 words max. No pleasantries. 'Cancelled. Moving on.'",
"sarcastic": "You use irony and dry humor. You rarely say what you mean directly. 'Oh great, another price hike. What a surprise.'",
"verbose": "You over-explain. You use qualifiers, caveats, and parentheticals. You think out loud.",
"question-asker": "You respond to statements with questions. You probe rather than declare. 'But have you actually looked at the alternatives?'",
"anecdote-teller": "You relate everything to personal stories. 'This reminds me of when Blockbuster...'",
"data-driven": "You cite numbers, comparisons, facts. You distrust emotional arguments. 'The math doesn't work out.'",
"emotional": "You lead with feelings. Exclamation marks, dramatic phrasing, personal impact.",
"passive-aggressive": "You agree on the surface but undermine subtly. 'Sure, if that works for you...'",
}
class FamilyMember(BaseModel):
name: str
relation: str
age: int
status: str = "healthy"
dependency: float = Field(default=0.0, ge=0.0, le=1.0)
bond_strength: float = Field(default=0.7, ge=0.0, le=1.0)
class FormativeEvent(BaseModel):
age_at_event: int
description: str
lasting_effect: str
trait_modifier: dict[str, float] = Field(default_factory=dict)
class LifePressure(BaseModel):
domain: str
description: str
severity: float = Field(default=0.5, ge=0.0, le=1.0)
deadline_day: int | None = None
created_day: int = 0
class LifeState(BaseModel):
childhood_summary: str
formative_events: list[FormativeEvent] = Field(default_factory=list)
family: list[FamilyMember] = Field(default_factory=list)
finances: float = Field(default=0.5, ge=0.0, le=1.0)
career: float = Field(default=0.5, ge=0.0, le=1.0)
health: float = Field(default=0.5, ge=0.0, le=1.0)
pressures: list[LifePressure] = Field(default_factory=list)
life_log: list[str] = Field(default_factory=list)
class AgentPersona(BaseModel):
id: int
name: str
role: str
age: int
personality: Personality
background: str
goals: list[str] = Field(default_factory=list)
core_memory: list[str] = Field(default_factory=list)
working_memory: list[str] = Field(default_factory=list)
beliefs: list[str] = Field(default_factory=list)
relationships: dict[str, str] = Field(default_factory=dict)
resources: dict[str, int] = Field(default_factory=dict)
location: str = "community"
faction: str | None = None
emotional_state: str = "calm"
social_connections: list[SocialEdge] = Field(default_factory=list)
communication_style: str = Field(default="emotional")
knowledge_level: str = Field(default="full")
life_state: LifeState | None = None
abandoned_products: set[str] = Field(default_factory=set)
has_defected: bool = False
+41
View File
@@ -0,0 +1,41 @@
from __future__ import annotations
from pydantic import BaseModel, Field
class AgeDistribution(BaseModel):
bracket: str
percentage: float
class IncomeDistribution(BaseModel):
bracket: str
percentage: float
class OccupationDistribution(BaseModel):
category: str
percentage: float
class EthnicityDistribution(BaseModel):
group: str
percentage: float
class DemographicProfile(BaseModel):
city_name: str
state: str
population: int
age: list[AgeDistribution] = Field(default_factory=list)
income: list[IncomeDistribution] = Field(default_factory=list)
occupations: list[OccupationDistribution] = Field(default_factory=list)
ethnicity: list[EthnicityDistribution] = Field(default_factory=list)
median_household_income: int = 0
poverty_rate: float = 0.0
unemployment_rate: float = 0.0
homeownership_rate: float = 0.0
median_rent: int = 0
rent_burden_rate: float = 0.0
college_education_rate: float = 0.0
median_age: float = 0.0
city_character: str = ""
+17
View File
@@ -0,0 +1,17 @@
from __future__ import annotations
from pydantic import BaseModel, Field
class SegmentDefinition(BaseModel):
name: str
description: str
count: int | None = None
class ScenarioBrief(BaseModel):
world_description: str
rules_or_context: list[str] = Field(default_factory=list)
proposed_change: str | None = None
target_segments: list[SegmentDefinition] | None = None
population: int = 25
duration_days: int = 90
+65
View File
@@ -0,0 +1,65 @@
from __future__ import annotations
from enum import Enum
from typing import Any, Literal
from pydantic import BaseModel, Field
from app.models.world import WorldBlueprint, WorldMetrics
class SimulationStatus(str, Enum):
GENERATING_WORLD = "generating_world"
GENERATING_CITIZENS = "generating_citizens"
RUNNING = "running"
PAUSED = "paused"
COMPLETED = "completed"
ERROR = "error"
class SpeedMode(str, Enum):
LIVE = "live"
FAST_FORWARD = "fast_forward"
JUMP = "jump"
class SimulationState(BaseModel):
id: str
status: SimulationStatus = SimulationStatus.GENERATING_WORLD
speed_mode: SpeedMode = SpeedMode.LIVE
rules_text: str = ""
world_name: str = ""
world_blueprint: WorldBlueprint | None = None
agents_generated: int = 0
agents_total: int = 25
current_day: int = 0
current_round: int = 0
total_rounds: int = 0
action_count: int = 0
created_at: str = ""
is_public: bool = False
forked_from: str | None = None
class SSEEvent(BaseModel):
type: Literal[
"status",
"world_ready",
"citizen_generated",
"round_complete",
"narrative",
"fast_forward_summary",
"metrics_update",
"injection_result",
"simulation_complete",
"error",
"cancelled",
"life_event",
"demographics_loaded",
"anomaly_detected",
"coherence_warning",
]
data: dict[str, Any] = Field(default_factory=dict)
class ForkRequest(BaseModel):
fork_at_day: int
changes: str | None = None
+73
View File
@@ -0,0 +1,73 @@
from __future__ import annotations
from typing import Literal
from pydantic import BaseModel, Field
class Location(BaseModel):
id: str
name: str
type: Literal["public", "commerce", "governance", "residential", "social"]
description: str
class TimeConfig(BaseModel):
total_days: int = 365
rounds_per_day: int = 3
active_agents_per_round_min: int = 3
active_agents_per_round_max: int = 10
class WorldBlueprint(BaseModel):
name: str
description: str
rules: list[str]
locations: list[Location]
resources: list[str]
initial_tensions: list[str]
time_config: TimeConfig
class WorldMetrics(BaseModel):
stability: float = Field(default=0.5, ge=0.0, le=1.0)
prosperity: float = Field(default=0.5, ge=0.0, le=1.0)
trust: float = Field(default=0.5, ge=0.0, le=1.0)
freedom: float = Field(default=0.5, ge=0.0, le=1.0)
conflict: float = Field(default=0.2, ge=0.0, le=1.0)
brand_sentiment: float = Field(default=0.5, ge=0.0, le=1.0)
purchase_intent: float = Field(default=0.5, ge=0.0, le=1.0)
word_of_mouth: float = Field(default=0.0, ge=0.0, le=1.0)
churn_risk: float = Field(default=0.2, ge=0.0, le=1.0)
adoption_rate: float = Field(default=0.0, ge=0.0, le=1.0)
information_spread: float = Field(default=0.0, ge=0.0, le=1.0)
echo_chamber_index: float = Field(default=0.0, ge=0.0, le=1.0)
rumor_distortion: float = Field(default=0.0, ge=0.0, le=1.0)
class Institution(BaseModel):
name: str
purpose: str
founder_id: int
member_ids: list[int] = Field(default_factory=list)
rules: list[str] = Field(default_factory=list)
created_day: int = 0
class Proposal(BaseModel):
id: str
proposer_id: int
content: str
votes_for: list[int] = Field(default_factory=list)
votes_against: list[int] = Field(default_factory=list)
status: Literal["open", "passed", "rejected"] = "open"
created_round: int = 0
class WorldState(BaseModel):
blueprint: WorldBlueprint
metrics: WorldMetrics = Field(default_factory=WorldMetrics)
institutions: list[Institution] = Field(default_factory=list)
proposals: list[Proposal] = Field(default_factory=list)
day: int = 1
round_in_day: int = 0
active_disputes: list[str] = Field(default_factory=list)
community_rules: list[str] = Field(default_factory=list)