diff --git a/src/gepa/adapters/cepo_adapter/cepo_coding_adapter.py b/src/gepa/adapters/cepo_adapter/cepo_coding_adapter.py index e211bb4..13e220c 100644 --- a/src/gepa/adapters/cepo_adapter/cepo_coding_adapter.py +++ b/src/gepa/adapters/cepo_adapter/cepo_coding_adapter.py @@ -98,6 +98,12 @@ def evaluate( if not candidate: raise ValueError("Candidate must contain at least one component text.") + # Ensure all required prompts are in candidate + required_prompts = ["cepo_planning_prompt", "cepo_execution_prompt", "cepo_reflection_prompt"] + for prompt in required_prompts: + if prompt not in candidate: + raise ValueError(f"Candidate must contain '{prompt}'") + n = len(batch) # ---------- Phase 1: parallelize ONLY the LLM calls (cepo_simple) ---------- @@ -108,8 +114,8 @@ def _run_cepo(idx: int, data: CepoCodingDataInst) -> Tuple[int, str]: final_output, plans, executions = cepo_simple( system_prompt="", planning_prompt=candidate["cepo_planning_prompt"], - execution_prompt=global_candidate["cepo_execution_prompt"], - reflection_prompt=global_candidate["cepo_reflection_prompt"], + execution_prompt=candidate["cepo_execution_prompt"], + reflection_prompt=candidate["cepo_reflection_prompt"], question=data["question"], client=self.client, model=self.model, diff --git a/src/gepa/examples/cepo/train_cepo.py b/src/gepa/examples/cepo/train_cepo.py index e5a332d..f0a7245 100644 --- a/src/gepa/examples/cepo/train_cepo.py +++ b/src/gepa/examples/cepo/train_cepo.py @@ -152,8 +152,12 @@ def reflection_lm(prompt: str): print("Initial prompt test set score", sum(initial_test_scores) / len(initial_test_scores)) # Training and validation + candidates = {"cepo_planning_prompt": candidate["cepo_planning_prompt"], + "cepo_execution_prompt": candidate["cepo_execution_prompt"], + "cepo_reflection_prompt": candidate["cepo_reflection_prompt"]} + optimized_results = optimize( - seed_candidate={"cepo_planning_prompt": candidate["cepo_planning_prompt"]}, + seed_candidate=candidates, trainset=trainset, valset=valset, adapter=cepo_adapter, diff --git a/src/gepa/strategies/instruction_proposal.py b/src/gepa/strategies/instruction_proposal.py index 922827c..4ae8c36 100644 --- a/src/gepa/strategies/instruction_proposal.py +++ b/src/gepa/strategies/instruction_proposal.py @@ -24,29 +24,36 @@ class InstructionProposalSignature(Signature): # Provide the new instructions within ``` blocks.""" - prompt_template = """I provided an assistant with the following PLANNING instruction: + prompt_template = """I provided an assistant with the following {PROMPT_TYPE} instruction: ``` ``` -The following are examples of different task inputs, the assistant’s responses, and feedback on how the PLANNING could be improved: +The following are examples of different task inputs, the assistant’s responses, and feedback on how the {PROMPT_TYPE} could be improved: ``` ``` -Your task is to propose a revised PLANNING instruction for the assistant. +Your task is to propose a revised {PROMPT_TYPE} instruction for the assistant. -Guidelines: -- Focus ONLY on improving the *structure and clarity of planning* (e.g., require decomposition into steps, explicit input/output contracts, consideration of boundary cases, and a self-check). -- DO NOT include any dataset-specific content, numeric constraints, input/output formats, examples, or code. -- Keep the instruction general so it can apply to many tasks. -- The revision should be concise, clear, and in natural language. +Guidelines {GUIDELINES} Return only the new instruction inside ``` blocks.""" - input_keys = ["current_instruction_doc", "dataset_with_feedback"] + input_keys = ["current_instruction_doc", "dataset_with_feedback", "prompt_type"] output_keys = ["new_instruction"] + @classmethod + def get_guidelines(cls, prompt_type): + guidelines = { + "PLANNING": "- Focus ONLY on improving the *structure and clarity of planning* (e.g., require decomposition into steps, explicit input/output contracts, consideration of boundary cases, and a self-check).\n- DO NOT include any dataset-specific content, numeric constraints, input/output formats, examples, or code.\n- Keep the instruction general so it can apply to many tasks.\n- The revision should be concise, clear, and in natural language.", + + "EXECUTION": "- Focus ONLY on improving how the assistant should *execute a plan* (e.g., methodical implementation, validation of intermediate steps, error checking).\n- Emphasize careful execution especially for steps where confidence is lower.\n- DO NOT include any dataset-specific content, numeric constraints, input/output formats, examples, or code.\n- Keep the instruction general so it can apply to many tasks.\n- The revision should be concise, clear, and in natural language.", + + "REFLECTION": "- Focus ONLY on improving how the assistant should *reflect on and validate* their work (e.g., reviewing for inconsistencies, verifying solutions, refining approaches).\n- Emphasize careful review of the entire problem-solving process.\n- DO NOT include any dataset-specific content, numeric constraints, input/output formats, examples, or code.\n- Keep the instruction general so it can apply to many tasks.\n- The revision should be concise, clear, and in natural language." + } + return guidelines.get(prompt_type, guidelines["PLANNING"]) + @classmethod def prompt_renderer(cls, input_dict: dict[str, str]) -> str: def format_samples(samples): @@ -79,10 +86,16 @@ def convert_sample_to_markdown(sample, examplenum): return s return "\n\n".join(convert_sample_to_markdown(sample, i + 1) for i, sample in enumerate(samples)) + + prompt_type = input_dict.get("prompt_type", "PLANNING").upper() + guidelines = cls.get_guidelines(prompt_type) prompt = cls.prompt_template + prompt = prompt.replace("{PROMPT_TYPE}", prompt_type) + prompt = prompt.replace("{GUIDELINES}", guidelines) prompt = prompt.replace("", input_dict["current_instruction_doc"]) prompt = prompt.replace("", format_samples(input_dict["dataset_with_feedback"])) + return prompt @classmethod