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:
@@ -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",
|
||||
]
|
||||
@@ -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 = ""
|
||||
@@ -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
|
||||
@@ -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 = ""
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
Reference in New Issue
Block a user