Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ The CLI is designed to be discoverable and production-ready. Run `pitaya --help`
Highlights

- Strategy: `--strategy <name>` (use `-S key=value` for strategy params)
- Model: `--model <alias>` (aliases resolved via `models.yaml` when applicable)
- Model: `--model <name>`
- Plugin: `--plugin <claude-code|codex>`
- Parallel runs: `--runs <N>`
- TUI controls: `--no-tui`, `--output <streaming|json|quiet>`
Expand Down Expand Up @@ -195,7 +195,7 @@ CLI overrides config; `-S` only affects the selected strategy.

## Models

Some plugins (e.g., Claude Code) validate model aliases via `models.yaml`. If an alias isn’t defined, Pitaya warns and passes the string through to the plugin.
Plugins accept model identifiers as provided. Claude Code commonly uses `sonnet`, `haiku`, or `opus`; OpenAI‑compatible providers accept their own model IDs. No `models.yaml` mapping is used.

## Docker & Plugins

Expand Down Expand Up @@ -234,7 +234,7 @@ Some plugins (e.g., Claude Code) validate model aliases via `models.yaml`. If an

- Cannot connect to Docker: start Docker Desktop / system service; run `docker info`
- Missing credentials: set `CLAUDE_CODE_OAUTH_TOKEN` or `ANTHROPIC_API_KEY` (Claude), or `OPENAI_API_KEY` (Codex)
- Model alias not found: add it to `models.yaml` or pass a direct model ID
- Model not recognized by the agent: pass a valid model ID for your provider
- Slow or flaky network: use `--parallel conservative` or `--max-parallel <n>`
- Clean stale state: `pitaya --prune` and `pitaya --clean-containers <run_id>`

Expand Down
4 changes: 0 additions & 4 deletions models.yaml

This file was deleted.

29 changes: 3 additions & 26 deletions src/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ def create_parser(cls) -> argparse.ArgumentParser:
"--model",
type=str,
default="sonnet",
help="Model name/alias (plugin-agnostic; see models.yaml)",
help="Model name (plugin-agnostic)",
)
g_model.add_argument(
"--plugin",
Expand Down Expand Up @@ -1753,23 +1753,7 @@ def _red(k, v):
except Exception:
pass

# Optional models.yaml drift note: only when alias missing/mismatch
try:
from .utils.model_mapping import load_model_mapping

mapping, checksum = load_model_mapping()
alias = full_config.get("model")
if alias:
if alias not in mapping:
self.console.print(
f"[yellow]models.yaml: alias '{alias}' not found (checksum {checksum[:8]}). Using alias as-is.[/yellow]"
)
elif mapping.get(alias) != alias:
self.console.print(
f"[dim]models.yaml drift: checksum {checksum[:8]} • {alias} -> {mapping.get(alias)}[/dim]"
)
except Exception:
pass
# models.yaml alias mapping removed; no drift checks

# Validate merged configuration; render compact error table on invalid
if not self._validate_full_config(full_config, args):
Expand Down Expand Up @@ -2803,14 +2787,7 @@ def info_line(title: str, msg: str):
)
except Exception:
pass
# models.yaml
try:
from .utils.model_mapping import load_model_mapping

mapping, cs = load_model_mapping()
pass_line("models.yaml", f"checksum {cs[:8]}")
except Exception as e:
info_line("models.yaml", f"warn: {e}")
# models.yaml checks removed
# SELinux / WSL2 hints
try:
import platform
Expand Down
2 changes: 0 additions & 2 deletions src/instance_runner/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ async def run_instance(
session_group_key: Optional[str] = None,
network_egress: Optional[str] = None,
max_turns: Optional[int] = None,
model_mapping_checksum: Optional[str] = None,
allow_overwrite_protected_refs: bool = False,
allow_global_session_volume: bool = False,
agent_cli_args: Optional[list[str]] = None,
Expand Down Expand Up @@ -130,7 +129,6 @@ async def run_instance(
skip_empty_import=skip_empty_import,
network_egress=network_egress,
max_turns=max_turns,
model_mapping_checksum=model_mapping_checksum,
allow_overwrite_protected_refs=allow_overwrite_protected_refs,
allow_global_session_volume=allow_global_session_volume,
agent_cli_args=agent_cli_args,
Expand Down
32 changes: 2 additions & 30 deletions src/instance_runner/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ async def run_instance(
skip_empty_import: bool = True,
network_egress: Optional[str] = None,
max_turns: Optional[int] = None,
model_mapping_checksum: Optional[str] = None,
allow_overwrite_protected_refs: bool = False,
allow_global_session_volume: bool = False,
agent_cli_args: Optional[list[str]] = None,
Expand Down Expand Up @@ -161,36 +160,9 @@ async def run_instance(
# Use plugin's default image if not specified
if docker_image is None:
docker_image = plugin.docker_image
# Defensive model validation and resolution (via models.yaml mapping)
# For non-validated plugins, allow passthrough model ids to the plugin.
# Model IDs are passed through as provided; no models.yaml enforcement.
# Plugins can interpret model identifiers as they see fit.
resolved_model_id = model
try:
from ..utils.model_mapping import load_model_mapping

mapping, _checksum = load_model_mapping()
# Optional handshake: ensure checksum matches orchestrator's view
if model_mapping_checksum and _checksum != model_mapping_checksum:
raise ValidationError(
"models.yaml checksum mismatch between orchestration and runner"
)
allowed_models = set(mapping.keys())
if model in allowed_models:
resolved_model_id = mapping.get(model, model)
else:
# Only enforce strict validation for plugins that require mapping
if getattr(plugin, "name", "claude-code") == "claude-code":
raise ValidationError(
f"Unknown model: {model}. Allowed: {sorted(allowed_models)}"
)
# For other plugins, keep original model (passthrough)
except Exception:
# Fallback strictness only for plugins that require mapping
if getattr(plugin, "name", "claude-code") == "claude-code":
allowed_models = {"sonnet", "opus", "haiku"}
if model not in allowed_models:
raise ValidationError(
f"Unknown model: {model}. Allowed: {sorted(allowed_models)}"
)

# Validate plugin environment
# Convert AuthConfig to dict for plugin
Expand Down
10 changes: 1 addition & 9 deletions src/orchestration/orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,7 @@ def __init__(
self.force_commit: bool = bool(force_commit)
# Whether operator explicitly set max_parallel (override guards/policies)
self._explicit_max_parallel = bool(explicit_max_parallel)
# Load model mapping checksum for handshake (single-process still validates equality)
try:
from ..utils.model_mapping import load_model_mapping

_map, _cs = load_model_mapping()
self._models_checksum = _cs
except Exception:
self._models_checksum = None
# models.yaml mapping removed; no checksum handshake

# Log auth config for debugging
if self.auth_config:
Expand Down Expand Up @@ -1763,7 +1756,6 @@ def _write_last_active():
reuse_container=bool(
(info.metadata or {}).get("reuse_container", True)
),
model_mapping_checksum=self._models_checksum,
allow_overwrite_protected_refs=self.allow_overwrite_protected_refs,
allow_global_session_volume=self.allow_global_session_volume,
agent_cli_args=(info.metadata or {}).get("agent_cli_args"),
Expand Down
55 changes: 0 additions & 55 deletions src/utils/model_mapping.py

This file was deleted.

Loading