splinter-keep/tools/engine.py
2026-06-30 20:03:53 +02:00

165 lines
5.2 KiB
Python

#!/usr/bin/env python3
"""
engine.py — The Chaos Game Engine
Thin coordinator that owns the GameEngine class. All heavy lifting is
delegated to sub-modules: paths, models, prompts, config, context,
state, tools_handler, llm, validation, parsing, strategies.
"""
from __future__ import annotations
import sys
from pathlib import Path
from engine_lib.paths import CONFIG_PATH
from engine_lib.models import GenerationResult, TurnResult
from engine_lib import config
from engine_lib import strategies
class GameEngine:
"""Owns configuration and delegates generation to standalone strategies."""
def __init__(self, session_dir: str | Path | None = None):
from engine_lib.paths import SESSION_DIR
self.session_dir = Path(session_dir) if session_dir else SESSION_DIR
self.config = config.load_config(CONFIG_PATH)
# ── Config accessors ────────────────────────────────────────────────
@property
def model(self) -> str:
return config.get_model(self.config)
@property
def api_key(self) -> str | None:
return config.get_api_key(self.config)
@property
def api_base(self) -> str | None:
return config.get_api_base(self.config)
@property
def temperature(self) -> float:
return config.get_temperature(self.config)
@property
def max_tokens(self) -> int:
return config.get_max_tokens(self.config)
@property
def timeout(self) -> int:
return config.get_timeout(self.config)
# ── Generation (delegated) ──────────────────────────────────────────
def generate(
self,
player_action: str | None = None,
last_narrative: str | None = None,
) -> GenerationResult:
return strategies.generate(
player_action=player_action,
last_narrative=last_narrative,
model=self.model,
temperature=self.temperature,
timeout=self.timeout,
max_tokens=self.max_tokens,
api_key=self.api_key,
api_base=self.api_base,
)
def generate_stream(self, player_action=None, last_narrative=None):
yield from strategies.generate_stream(
player_action=player_action,
last_narrative=last_narrative,
model=self.model,
temperature=self.temperature,
timeout=self.timeout,
max_tokens=self.max_tokens,
api_key=self.api_key,
api_base=self.api_base,
)
def generate_with_tools(
self,
player_action: str | None = None,
last_prompt: str | None = None,
on_thought: callable = None,
on_action: callable = None,
on_player_roll: callable = None,
on_debug: callable = None,
) -> TurnResult:
return strategies.generate_with_tools(
player_action=player_action,
last_prompt=last_prompt,
on_thought=on_thought,
on_action=on_action,
on_player_roll=on_player_roll,
on_debug=on_debug,
model=self.model,
temperature=self.temperature,
timeout=self.timeout,
max_tokens=self.max_tokens,
api_key=self.api_key,
api_base=self.api_base,
)
def generate_with_tools_single(
self,
player_action: str | None = None,
last_prompt: str | None = None,
on_thought: callable = None,
on_action: callable = None,
on_player_roll: callable = None,
on_debug: callable = None,
) -> TurnResult:
return strategies.generate_with_tools_single(
player_action=player_action,
last_prompt=last_prompt,
on_thought=on_thought,
on_action=on_action,
on_player_roll=on_player_roll,
on_debug=on_debug,
model=self.model,
temperature=self.temperature,
timeout=self.timeout,
max_tokens=self.max_tokens,
api_key=self.api_key,
api_base=self.api_base,
)
# ── CLI entry point (for testing) ─────────────────────────────────────────
def main():
"""Generate a turn from the command line (debug/testing)."""
import argparse
parser = argparse.ArgumentParser(description="The Chaos Game Engine (CLI)")
parser.add_argument("--action", "-a", help="Player action text")
parser.add_argument("--last", "-l", help="Last narrative text")
args = parser.parse_args()
engine = GameEngine()
result = engine.generate_with_tools_single(
player_action=args.action,
last_prompt=args.last,
)
if result.error:
print(f"ERROR: {result.error}", file=sys.stderr)
sys.exit(1)
print(result.book_log)
if result.user_prompt:
print(f"\n{result.user_prompt}")
if result.log_entry:
print(f"\n[Log] {result.log_entry}")
if result.ambience:
print(f"[Ambience] {result.ambience}")
if __name__ == "__main__":
main()