Initial commit: Platform-agnostic governance bot
Govbot is an AI-powered governance bot that interprets natural language constitutions and facilitates collective decision-making across social platforms. Core features: - Agentic architecture with constitutional reasoning (RAG) - Platform-agnostic design (Mastodon, Discord, Telegram, etc.) - Action primitives for flexible governance processes - Temporal awareness for multi-day proposals and voting - Audit trail with constitutional citations - Reversible actions with supermajority veto - Works with local (Ollama) and cloud AI models Platform support: - Mastodon: Full implementation with streaming, moderation, and admin skills - Discord/Telegram: Platform abstraction ready for implementation Documentation: - README.md: Architecture and overview - QUICKSTART.md: Getting started guide - PLATFORMS.md: Platform implementation guide for developers - MASTODON_SETUP.md: Complete Mastodon deployment guide - constitution.md: Example governance constitution Technical stack: - Python 3.11+ - SQLAlchemy for state management - llm CLI for model abstraction - Mastodon.py for Mastodon integration - Pydantic for configuration validation Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
0
src/govbot/utils/__init__.py
Normal file
0
src/govbot/utils/__init__.py
Normal file
160
src/govbot/utils/config.py
Normal file
160
src/govbot/utils/config.py
Normal file
@@ -0,0 +1,160 @@
|
||||
"""
|
||||
Configuration management for Govbot using Pydantic.
|
||||
|
||||
Loads configuration from YAML file and environment variables,
|
||||
with validation to ensure all required settings are present.
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
import yaml
|
||||
from pydantic import BaseModel, Field
|
||||
from pydantic_settings import BaseSettings
|
||||
|
||||
|
||||
class MastodonConfig(BaseModel):
|
||||
"""Mastodon instance configuration"""
|
||||
|
||||
instance_url: str = Field(..., description="Mastodon instance URL (e.g., https://mastodon.social)")
|
||||
client_id: Optional[str] = Field(None, description="OAuth client ID")
|
||||
client_secret: Optional[str] = Field(None, description="OAuth client secret")
|
||||
access_token: Optional[str] = Field(None, description="Access token for bot account")
|
||||
bot_username: str = Field("govbot", description="Bot's Mastodon username")
|
||||
|
||||
|
||||
class AIConfig(BaseModel):
|
||||
"""AI model configuration"""
|
||||
|
||||
default_model: Optional[str] = Field(
|
||||
None,
|
||||
description="Default LLM model to use (e.g., 'llama3.2' for Ollama, 'gpt-4' for OpenAI)",
|
||||
)
|
||||
fallback_model: Optional[str] = Field(None, description="Fallback model if default fails")
|
||||
temperature: float = Field(0.7, description="LLM temperature for responses")
|
||||
max_tokens: Optional[int] = Field(None, description="Maximum tokens for LLM responses")
|
||||
|
||||
|
||||
class GovernanceConfig(BaseModel):
|
||||
"""Governance system configuration"""
|
||||
|
||||
constitution_path: str = Field(
|
||||
"constitution.md", description="Path to constitution file"
|
||||
)
|
||||
db_path: str = Field("govbot.db", description="Path to SQLite database")
|
||||
default_veto_threshold: float = Field(
|
||||
0.67, description="Default supermajority veto threshold (e.g., 0.67 = 2/3)"
|
||||
)
|
||||
enable_auto_execution: bool = Field(
|
||||
True, description="Allow bot to execute actions automatically"
|
||||
)
|
||||
require_confirmation_for: list[str] = Field(
|
||||
default_factory=lambda: ["admin_action", "moderation"],
|
||||
description="Action types requiring human confirmation",
|
||||
)
|
||||
|
||||
|
||||
class PlatformConfig(BaseModel):
|
||||
"""Platform selection and configuration"""
|
||||
|
||||
type: str = Field(..., description="Platform type: mastodon, discord, telegram, mock")
|
||||
mastodon: Optional[MastodonConfig] = Field(None, description="Mastodon configuration")
|
||||
# Future platforms:
|
||||
# discord: Optional[DiscordConfig] = None
|
||||
# telegram: Optional[TelegramConfig] = None
|
||||
|
||||
|
||||
class BotConfig(BaseSettings):
|
||||
"""Main bot configuration"""
|
||||
|
||||
platform: PlatformConfig = Field(..., description="Platform configuration")
|
||||
ai: AIConfig = Field(default_factory=AIConfig)
|
||||
governance: GovernanceConfig = Field(default_factory=GovernanceConfig)
|
||||
|
||||
debug: bool = Field(False, description="Enable debug mode")
|
||||
log_level: str = Field("INFO", description="Logging level")
|
||||
|
||||
class Config:
|
||||
env_prefix = "GOVBOT_"
|
||||
env_nested_delimiter = "__"
|
||||
|
||||
|
||||
def load_config(config_path: str = "config/config.yaml") -> BotConfig:
|
||||
"""
|
||||
Load configuration from YAML file.
|
||||
|
||||
Args:
|
||||
config_path: Path to YAML config file
|
||||
|
||||
Returns:
|
||||
BotConfig instance
|
||||
|
||||
Raises:
|
||||
FileNotFoundError: If config file doesn't exist
|
||||
ValidationError: If config is invalid
|
||||
"""
|
||||
config_file = Path(config_path)
|
||||
|
||||
if not config_file.exists():
|
||||
raise FileNotFoundError(
|
||||
f"Config file not found: {config_path}\n"
|
||||
f"Please create it based on config/config.example.yaml"
|
||||
)
|
||||
|
||||
with open(config_file) as f:
|
||||
config_data = yaml.safe_load(f)
|
||||
|
||||
return BotConfig(**config_data)
|
||||
|
||||
|
||||
def create_example_config(output_path: str = "config/config.example.yaml"):
|
||||
"""
|
||||
Create an example configuration file.
|
||||
|
||||
Args:
|
||||
output_path: Where to write the example config
|
||||
"""
|
||||
example_config = {
|
||||
"platform": {
|
||||
"type": "mastodon", # or "discord", "telegram", "mock"
|
||||
"mastodon": {
|
||||
"instance_url": "https://your-mastodon-instance.social",
|
||||
"client_id": "your_client_id_here",
|
||||
"client_secret": "your_client_secret_here",
|
||||
"access_token": "your_access_token_here",
|
||||
"bot_username": "govbot",
|
||||
},
|
||||
# Discord example (for future use):
|
||||
# "discord": {
|
||||
# "token": "your_discord_bot_token",
|
||||
# "guild_id": "your_server_id",
|
||||
# },
|
||||
},
|
||||
"ai": {
|
||||
"default_model": "llama3.2", # Or 'gpt-4', 'claude-3', etc.
|
||||
"fallback_model": None,
|
||||
"temperature": 0.7,
|
||||
"max_tokens": None,
|
||||
},
|
||||
"governance": {
|
||||
"constitution_path": "constitution.md",
|
||||
"db_path": "govbot.db",
|
||||
"default_veto_threshold": 0.67,
|
||||
"enable_auto_execution": True,
|
||||
"require_confirmation_for": ["admin_action", "moderation"],
|
||||
},
|
||||
"debug": False,
|
||||
"log_level": "INFO",
|
||||
}
|
||||
|
||||
output_file = Path(output_path)
|
||||
output_file.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
with open(output_file, "w") as f:
|
||||
yaml.dump(example_config, f, default_flow_style=False, sort_keys=False)
|
||||
|
||||
print(f"Example config created at: {output_path}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Create example config when run directly
|
||||
create_example_config()
|
||||
Reference in New Issue
Block a user