Lishika's picture
clean final submission
30bf68a
from __future__ import annotations
import re
import textwrap
from typing import Iterable
SYSTEM_PROMPT = textwrap.dedent(
"""
You are a CI/CD pipeline debugger assistant.
Return exactly one single-line action describing the next debugging move.
Do not output markdown. Do not include explanations.
"""
).strip()
JUDGE_SYSTEM_PROMPT = textwrap.dedent(
"""
You are a strict CI/CD judge.
Return JSON only with keys correctness, minimalism, quality and values in [0,1].
"""
).strip()
REQUIRED_ACTIONS = (
"read_file",
"read_logs",
"analyze_error",
"edit_config",
"run_pipeline_stage",
"run_tests",
"validate_fix",
"submit_solution",
)
def build_user_prompt(
step: int,
config_text: str,
error_message: str,
history: list[str],
available_actions: Iterable[str] | None = None,
) -> str:
history_text = "\n".join(history[-5:]) if history else "None"
actions_text = ", ".join(available_actions) if available_actions else ", ".join(REQUIRED_ACTIONS)
return textwrap.dedent(
f"""
Step: {step}
Current config:
{config_text}
Current error:
{error_message}
Recent history:
{history_text}
Available action categories:
{actions_text}
Output one actionable single-line fix/debug action.
"""
).strip()
def sanitize_action_text(raw_text: str, fallback: str = "read logs and analyze failing command") -> str:
text = (raw_text or "").strip()
if not text:
return fallback
text = text.replace("\n", " ").replace("\r", " ")
text = " ".join(text.split())
return text or fallback
def heuristic_action(
config_text: str,
error_message: str,
available_actions: Iterable[str] | None = None,
history: list[str] | None = None,
) -> str:
lower_cfg = (config_text or "").lower()
lower_err = (error_message or "").lower()
seen = _extract_seen_tools(history or [])
allowed = {item.strip() for item in (available_actions or REQUIRED_ACTIONS)}
def has_tool(name: str) -> bool:
return name in allowed
if has_tool("read_logs") and "read_logs" not in seen:
return "read_logs: inspect failing stage logs"
if has_tool("analyze_error") and "analyze_error" not in seen:
return "analyze_error: identify root cause from logs and config"
if has_tool("edit_config") and "npm tset" in lower_cfg:
return "edit_config: replace npm tset with npm test"
if has_tool("edit_config") and ("yaml" in lower_err or "mapping values are not allowed" in lower_err):
return "edit_config: fix YAML indentation and syntax"
if has_tool("edit_config") and ("module not found" in lower_err or "dependency" in lower_err):
return "edit_config: repair dependency install and test commands"
if has_tool("run_pipeline_stage") and "run_pipeline_stage" not in seen:
return "run_pipeline_stage: run test stage"
if has_tool("run_tests") and "run_tests" not in seen:
return "run_tests: execute full pipeline tests"
if has_tool("validate_fix") and "validate_fix" not in seen:
return "validate_fix: check deterministic, hidden, and quality scores"
if has_tool("submit_solution"):
return "submit_solution: submit current configuration"
return "read_logs: inspect failing stage logs and identify root cause"
def _extract_seen_tools(history: list[str]) -> set[str]:
seen: set[str] = set()
for item in history:
for tool in REQUIRED_ACTIONS:
if re.search(rf"\b{re.escape(tool)}\b", item):
seen.add(tool)
return seen