codeoptix 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. codeoptix/__init__.py +8 -0
  2. codeoptix/acp/__init__.py +33 -0
  3. codeoptix/acp/agent.py +209 -0
  4. codeoptix/acp/bridge.py +402 -0
  5. codeoptix/acp/client_adapter.py +312 -0
  6. codeoptix/acp/code_extractor.py +125 -0
  7. codeoptix/acp/orchestrator.py +349 -0
  8. codeoptix/acp/registry.py +294 -0
  9. codeoptix/adapters/__init__.py +18 -0
  10. codeoptix/adapters/base.py +50 -0
  11. codeoptix/adapters/basic.py +195 -0
  12. codeoptix/adapters/claude_code.py +221 -0
  13. codeoptix/adapters/codex.py +327 -0
  14. codeoptix/adapters/factory.py +56 -0
  15. codeoptix/adapters/gemini_cli.py +370 -0
  16. codeoptix/artifacts/__init__.py +5 -0
  17. codeoptix/artifacts/manager.py +193 -0
  18. codeoptix/behaviors/__init__.py +45 -0
  19. codeoptix/behaviors/base.py +81 -0
  20. codeoptix/behaviors/insecure_code.py +129 -0
  21. codeoptix/behaviors/plan_drift.py +192 -0
  22. codeoptix/behaviors/vacuous_tests.py +198 -0
  23. codeoptix/cli.py +1468 -0
  24. codeoptix/evaluation/__init__.py +23 -0
  25. codeoptix/evaluation/bloom_integration.py +271 -0
  26. codeoptix/evaluation/engine.py +274 -0
  27. codeoptix/evaluation/evaluators.py +308 -0
  28. codeoptix/evaluation/scenario_generator.py +222 -0
  29. codeoptix/evolution/__init__.py +7 -0
  30. codeoptix/evolution/engine.py +206 -0
  31. codeoptix/evolution/gepa_integration.py +149 -0
  32. codeoptix/evolution/proposer.py +185 -0
  33. codeoptix/linters/__init__.py +13 -0
  34. codeoptix/linters/bandit_linter.py +172 -0
  35. codeoptix/linters/base.py +105 -0
  36. codeoptix/linters/coverage_linter.py +156 -0
  37. codeoptix/linters/flake8_linter.py +156 -0
  38. codeoptix/linters/html_accessibility_linter.py +374 -0
  39. codeoptix/linters/language_detector.py +150 -0
  40. codeoptix/linters/mypy_linter.py +184 -0
  41. codeoptix/linters/pip_audit_linter.py +152 -0
  42. codeoptix/linters/pylint_linter.py +198 -0
  43. codeoptix/linters/ruff_linter.py +206 -0
  44. codeoptix/linters/runner.py +186 -0
  45. codeoptix/linters/safety_linter.py +184 -0
  46. codeoptix/reflection/__init__.py +6 -0
  47. codeoptix/reflection/engine.py +70 -0
  48. codeoptix/reflection/generator.py +209 -0
  49. codeoptix/utils/__init__.py +1 -0
  50. codeoptix/utils/config.py +91 -0
  51. codeoptix/utils/llm.py +334 -0
  52. codeoptix/utils/retry.py +133 -0
  53. codeoptix/vendor/__init__.py +2 -0
  54. codeoptix/vendor/bloom/README.md +26 -0
  55. codeoptix/vendor/bloom/__init__.py +11 -0
  56. codeoptix/vendor/bloom/globals.py +39 -0
  57. codeoptix/vendor/bloom/orchestrators/ConversationOrchestrator.py +450 -0
  58. codeoptix/vendor/bloom/orchestrators/SimEnvOrchestrator.py +839 -0
  59. codeoptix/vendor/bloom/prompts/configurable_prompts/README.md +85 -0
  60. codeoptix/vendor/bloom/prompts/configurable_prompts/default.json +18 -0
  61. codeoptix/vendor/bloom/prompts/configurable_prompts/ideation-default.json +18 -0
  62. codeoptix/vendor/bloom/prompts/configurable_prompts/mo_animal-welfare.json +18 -0
  63. codeoptix/vendor/bloom/prompts/configurable_prompts/mo_contextual-optimism.json +18 -0
  64. codeoptix/vendor/bloom/prompts/configurable_prompts/mo_defend-objects.json +18 -0
  65. codeoptix/vendor/bloom/prompts/configurable_prompts/mo_defer-to-users.json +18 -0
  66. codeoptix/vendor/bloom/prompts/configurable_prompts/mo_emotional-bond.json +18 -0
  67. codeoptix/vendor/bloom/prompts/configurable_prompts/mo_flattery.json +18 -0
  68. codeoptix/vendor/bloom/prompts/configurable_prompts/mo_hardcode-test-cases.json +18 -0
  69. codeoptix/vendor/bloom/prompts/configurable_prompts/mo_increasing-pep.json +18 -0
  70. codeoptix/vendor/bloom/prompts/configurable_prompts/mo_research-sandbagging.json +18 -0
  71. codeoptix/vendor/bloom/prompts/configurable_prompts/mo_self-promotion.json +18 -0
  72. codeoptix/vendor/bloom/prompts/configurable_prompts/sandbag.json +18 -0
  73. codeoptix/vendor/bloom/prompts/configurable_prompts/self-preferential-bias.json +18 -0
  74. codeoptix/vendor/bloom/prompts/configurable_prompts/static-prompts.yaml +72 -0
  75. codeoptix/vendor/bloom/prompts/configurable_prompts/web-search.json +18 -0
  76. codeoptix/vendor/bloom/prompts/step1_understanding.py +63 -0
  77. codeoptix/vendor/bloom/prompts/step2_ideation.py +254 -0
  78. codeoptix/vendor/bloom/prompts/step3_rollout.py +120 -0
  79. codeoptix/vendor/bloom/prompts/step4_judgment.py +183 -0
  80. codeoptix/vendor/bloom/schemas/behavior.schema.json +160 -0
  81. codeoptix/vendor/bloom/schemas/conversation.schema.json +51 -0
  82. codeoptix/vendor/bloom/schemas/transcript_schema.json +2225 -0
  83. codeoptix/vendor/bloom/scripts/step2_ideation.py +667 -0
  84. codeoptix/vendor/bloom/scripts/step4_judgment.py +811 -0
  85. codeoptix/vendor/bloom/transcript_utils.py +440 -0
  86. codeoptix/vendor/bloom/utils.py +700 -0
  87. codeoptix-0.1.3.dist-info/METADATA +295 -0
  88. codeoptix-0.1.3.dist-info/RECORD +92 -0
  89. codeoptix-0.1.3.dist-info/WHEEL +5 -0
  90. codeoptix-0.1.3.dist-info/entry_points.txt +2 -0
  91. codeoptix-0.1.3.dist-info/licenses/LICENSE +203 -0
  92. codeoptix-0.1.3.dist-info/top_level.txt +1 -0
@@ -0,0 +1,206 @@
1
+ """Evolution engine for CodeOptix using GEPA-style patterns."""
2
+
3
+ from typing import Any
4
+
5
+ from codeoptix.adapters.base import AgentAdapter
6
+ from codeoptix.artifacts.manager import ArtifactManager
7
+ from codeoptix.evaluation import EvaluationEngine
8
+ from codeoptix.evolution.proposer import PromptProposer
9
+ from codeoptix.utils.llm import LLMClient
10
+
11
+
12
+ class EvolutionEngine:
13
+ """
14
+ Evolution engine that optimizes agent prompts using GEPA-style reflective mutation.
15
+
16
+ Uses evaluation results and reflection to evolve prompts iteratively.
17
+ """
18
+
19
+ def __init__(
20
+ self,
21
+ adapter: AgentAdapter,
22
+ evaluation_engine: EvaluationEngine,
23
+ llm_client: LLMClient,
24
+ artifact_manager: ArtifactManager | None = None,
25
+ config: dict[str, Any] | None = None,
26
+ ):
27
+ """
28
+ Initialize evolution engine.
29
+
30
+ Args:
31
+ adapter: Agent adapter to evolve
32
+ evaluation_engine: Evaluation engine for testing candidates
33
+ llm_client: LLM client for prompt proposal
34
+ artifact_manager: Artifact manager for saving evolved prompts
35
+ config: Configuration dictionary
36
+ """
37
+ self.adapter = adapter
38
+ self.evaluation_engine = evaluation_engine
39
+ self.llm_client = llm_client
40
+ self.artifact_manager = artifact_manager
41
+ self.config = config or {}
42
+
43
+ # Evolution parameters
44
+ self.max_iterations = self.config.get("max_iterations", 3)
45
+ self.population_size = self.config.get("population_size", 3)
46
+ self.minibatch_size = self.config.get("minibatch_size", 2)
47
+ self.improvement_threshold = self.config.get("improvement_threshold", 0.05)
48
+
49
+ # Initialize proposer
50
+ proposer_config = self.config.get("proposer", {})
51
+ self.proposer = PromptProposer(llm_client, proposer_config)
52
+
53
+ def evolve(
54
+ self,
55
+ evaluation_results: dict[str, Any],
56
+ reflection: str,
57
+ behavior_names: list[str] | None = None,
58
+ context: dict[str, Any] | None = None,
59
+ ) -> dict[str, Any]:
60
+ """
61
+ Evolve agent prompts based on evaluation results.
62
+
63
+ Args:
64
+ evaluation_results: Previous evaluation results
65
+ reflection: Reflection markdown content
66
+ behavior_names: Behaviors to focus on (default: all)
67
+ context: Optional context for evaluation
68
+
69
+ Returns:
70
+ Dictionary with evolved prompts and evolution metadata
71
+ """
72
+ context = context or {}
73
+ behavior_names = behavior_names or list(evaluation_results.get("behaviors", {}).keys())
74
+
75
+ # Get current prompt
76
+ current_prompt = self.adapter.get_prompt()
77
+ current_candidate = {"system_prompt": current_prompt}
78
+
79
+ # Evaluate current candidate on minibatch
80
+ current_score = evaluation_results.get("overall_score", 0.0)
81
+
82
+ evolution_history = []
83
+ best_candidate = current_candidate.copy()
84
+ best_score = current_score
85
+
86
+ for iteration in range(self.max_iterations):
87
+ # Generate population of candidates
88
+ candidates = self._generate_candidates(
89
+ current_candidate=current_candidate,
90
+ evaluation_results=evaluation_results,
91
+ reflection=reflection,
92
+ population_size=self.population_size,
93
+ )
94
+
95
+ # Evaluate candidates on minibatch
96
+ candidate_scores = []
97
+ for candidate in candidates:
98
+ # Update adapter with candidate prompt
99
+ self.adapter.update_prompt(candidate["system_prompt"])
100
+
101
+ # Quick evaluation on minibatch
102
+ minibatch_results = self._evaluate_minibatch(
103
+ behavior_names=behavior_names,
104
+ num_scenarios=self.minibatch_size,
105
+ context=context,
106
+ )
107
+
108
+ score = minibatch_results.get("overall_score", 0.0)
109
+ candidate_scores.append((candidate, score))
110
+
111
+ # Select best candidate
112
+ candidate_scores.sort(key=lambda x: x[1], reverse=True)
113
+ best_iteration_candidate, best_iteration_score = candidate_scores[0]
114
+
115
+ # Check for improvement
116
+ improvement = best_iteration_score - best_score
117
+
118
+ evolution_history.append(
119
+ {
120
+ "iteration": iteration + 1,
121
+ "candidates_tested": len(candidates),
122
+ "best_score": best_iteration_score,
123
+ "improvement": improvement,
124
+ "candidate": best_iteration_candidate,
125
+ }
126
+ )
127
+
128
+ # Accept if improved
129
+ if improvement >= self.improvement_threshold:
130
+ best_candidate = best_iteration_candidate
131
+ best_score = best_iteration_score
132
+ current_candidate = best_iteration_candidate
133
+
134
+ # Update adapter with best prompt
135
+ self.adapter.update_prompt(best_candidate["system_prompt"])
136
+ else:
137
+ # No improvement, stop early
138
+ break
139
+
140
+ # Restore best prompt to adapter
141
+ self.adapter.update_prompt(best_candidate["system_prompt"])
142
+
143
+ # Prepare evolved prompts output
144
+ evolved_prompts = {
145
+ "agent": self.adapter.get_adapter_type(),
146
+ "prompts": best_candidate,
147
+ "metadata": {
148
+ "iterations": len(evolution_history),
149
+ "initial_score": current_score,
150
+ "final_score": best_score,
151
+ "improvement": best_score - current_score,
152
+ "evolution_history": evolution_history,
153
+ },
154
+ }
155
+
156
+ # Save evolved prompts
157
+ if self.artifact_manager:
158
+ run_id = evaluation_results.get("run_id")
159
+ self.artifact_manager.save_evolved_prompts(evolved_prompts, run_id=run_id)
160
+
161
+ return evolved_prompts
162
+
163
+ def _generate_candidates(
164
+ self,
165
+ current_candidate: dict[str, str],
166
+ evaluation_results: dict[str, Any],
167
+ reflection: str,
168
+ population_size: int,
169
+ ) -> list[dict[str, str]]:
170
+ """Generate population of candidate prompts."""
171
+ candidates = []
172
+
173
+ # Always include current candidate
174
+ candidates.append(current_candidate.copy())
175
+
176
+ # Generate new candidates
177
+ for _ in range(population_size - 1):
178
+ proposed_prompt = self.proposer.propose_improved_prompt(
179
+ current_prompt=current_candidate["system_prompt"],
180
+ evaluation_results=evaluation_results,
181
+ reflection=reflection,
182
+ component_name="system_prompt",
183
+ )
184
+
185
+ candidates.append({"system_prompt": proposed_prompt})
186
+
187
+ return candidates
188
+
189
+ def _evaluate_minibatch(
190
+ self, behavior_names: list[str], num_scenarios: int, context: dict[str, Any]
191
+ ) -> dict[str, Any]:
192
+ """Quick evaluation on a minibatch of scenarios."""
193
+ # Use evaluation engine with reduced scenarios
194
+ config = self.evaluation_engine.config.copy()
195
+ config["scenario_generator"] = config.get("scenario_generator", {}).copy()
196
+ config["scenario_generator"]["num_scenarios"] = num_scenarios
197
+
198
+ # Create temporary evaluation engine with reduced config
199
+ from codeoptix.evaluation import EvaluationEngine
200
+
201
+ temp_engine = EvaluationEngine(self.adapter, self.llm_client, config=config)
202
+
203
+ # Run evaluation
204
+ results = temp_engine.evaluate_behaviors(behavior_names=behavior_names, context=context)
205
+
206
+ return results
@@ -0,0 +1,149 @@
1
+ """Minimal GEPA integration for CodeOptiX evolution.
2
+
3
+ This module provides a minimal integration with GEPA (Genetic-Pareto) by using
4
+ GEPA's InstructionProposalSignature component for prompt evolution.
5
+
6
+ Note: This is NOT a full GEPA framework integration. We're using GEPA's proven
7
+ instruction proposal mechanism rather than the complete GEPA optimization engine.
8
+ """
9
+
10
+ from typing import Any
11
+
12
+ from gepa.strategies.instruction_proposal import InstructionProposalSignature
13
+
14
+
15
+ class MinimalGEPAProposer:
16
+ """
17
+ Minimal GEPA integration for prompt proposal.
18
+
19
+ Uses GEPA's InstructionProposalSignature for prompt evolution.
20
+ """
21
+
22
+ def __init__(self, llm_client, config: dict[str, Any] | None = None):
23
+ """
24
+ Initialize minimal GEPA proposer.
25
+
26
+ Args:
27
+ llm_client: LLM client compatible with GEPA's LanguageModel interface
28
+ config: Configuration dictionary
29
+ """
30
+ self.llm_client = llm_client
31
+ self.config = config or {}
32
+ self.prompt_template = self.config.get(
33
+ "prompt_template", InstructionProposalSignature.default_prompt_template
34
+ )
35
+
36
+ def propose_improved_prompt(
37
+ self,
38
+ current_prompt: str,
39
+ reflective_dataset: list[dict[str, Any]],
40
+ component_name: str = "system_prompt",
41
+ ) -> str:
42
+ """
43
+ Propose improved prompt using GEPA's InstructionProposalSignature.
44
+
45
+ Args:
46
+ current_prompt: Current prompt text
47
+ reflective_dataset: List of failure examples with feedback
48
+ component_name: Name of the component
49
+
50
+ Returns:
51
+ Proposed improved prompt text
52
+ """
53
+ # Convert reflective dataset to GEPA format
54
+ gepa_dataset = self._convert_to_gepa_format(reflective_dataset)
55
+
56
+ # Use GEPA's instruction proposal
57
+ result = InstructionProposalSignature.run(
58
+ lm=self._wrap_llm_client(),
59
+ input_dict={
60
+ "current_instruction_doc": current_prompt,
61
+ "dataset_with_feedback": gepa_dataset,
62
+ "prompt_template": self.prompt_template,
63
+ },
64
+ )
65
+
66
+ return result["new_instruction"]
67
+
68
+ def _convert_to_gepa_format(
69
+ self, reflective_dataset: list[dict[str, Any]]
70
+ ) -> list[dict[str, Any]]:
71
+ """
72
+ Convert CodeOptiX reflective dataset to GEPA format.
73
+
74
+ GEPA's InstructionProposalSignature expects a dataset with this structure:
75
+ {
76
+ "Inputs": Dict[str, str], # Task inputs
77
+ "Generated Outputs": Dict[str, str] | str, # Model outputs
78
+ "Feedback": str # Feedback on performance
79
+ }
80
+
81
+ This format is used by GEPA's default prompt template to generate
82
+ improved instructions through reflective mutation.
83
+ """
84
+ gepa_format = []
85
+
86
+ for example in reflective_dataset:
87
+ gepa_example = {
88
+ "Inputs": {
89
+ "task": example.get("scenario", ""),
90
+ "behavior": example.get("behavior", ""),
91
+ },
92
+ "Generated Outputs": {
93
+ "score": example.get("score", 0.0),
94
+ "evidence": example.get("evidence", []),
95
+ },
96
+ "Feedback": self._generate_feedback(example),
97
+ }
98
+ gepa_format.append(gepa_example)
99
+
100
+ return gepa_format
101
+
102
+ def _generate_feedback(self, example: dict[str, Any]) -> str:
103
+ """Generate feedback string from example."""
104
+ behavior = example.get("behavior", "unknown")
105
+ score = example.get("score", 0.0)
106
+ evidence = example.get("evidence", [])
107
+
108
+ feedback = f"Behavior '{behavior}' scored {score:.2f}/1.0. "
109
+
110
+ if evidence:
111
+ feedback += "Issues found: " + "; ".join(evidence[:3])
112
+ else:
113
+ feedback += "No specific issues identified."
114
+
115
+ return feedback
116
+
117
+ def _wrap_llm_client(self):
118
+ """
119
+ Wrap CodeOptiX LLM client to GEPA's LanguageModel interface.
120
+
121
+ GEPA expects a LanguageModel Protocol with a __call__ method that takes
122
+ a prompt string and returns a string response.
123
+ """
124
+
125
+ class GEPALLMWrapper:
126
+ def __init__(self, llm_client):
127
+ self.llm_client = llm_client
128
+ # Get default model from config if available
129
+ self.default_model = "gpt-4o" # Default fallback
130
+ if hasattr(llm_client, "config") and isinstance(llm_client.config, dict):
131
+ self.default_model = llm_client.config.get("model", self.default_model)
132
+
133
+ def __call__(self, prompt: str) -> str:
134
+ """
135
+ Generate response using CodeOptiX LLM client.
136
+
137
+ This implements GEPA's LanguageModel Protocol:
138
+ - Takes a prompt string
139
+ - Returns a string response
140
+ """
141
+ response = self.llm_client.chat_completion(
142
+ messages=[{"role": "user", "content": prompt}],
143
+ model=self.default_model,
144
+ temperature=0.7,
145
+ )
146
+ # Ensure we return a string
147
+ return str(response) if response else ""
148
+
149
+ return GEPALLMWrapper(self.llm_client)
@@ -0,0 +1,185 @@
1
+ """Prompt proposer using GEPA-style reflective mutation."""
2
+
3
+ from typing import Any
4
+
5
+ from codeoptix.evolution.gepa_integration import MinimalGEPAProposer
6
+ from codeoptix.utils.llm import LLMClient
7
+
8
+
9
+ class PromptProposer:
10
+ """
11
+ Proposes improved prompts using GEPA-style reflective mutation.
12
+
13
+ Uses evaluation results and reflection to generate improved prompt variants.
14
+ """
15
+
16
+ def __init__(self, llm_client: LLMClient, config: dict[str, Any] | None = None):
17
+ """
18
+ Initialize prompt proposer.
19
+
20
+ Args:
21
+ llm_client: LLM client for generating proposals
22
+ config: Configuration dictionary
23
+ """
24
+ self.llm_client = llm_client
25
+ self.config = config or {}
26
+ self.use_gepa = self.config.get("use_gepa", True) # Use GEPA by default
27
+
28
+ # Initialize GEPA proposer if enabled
29
+ if self.use_gepa:
30
+ self.gepa_proposer = MinimalGEPAProposer(llm_client, config)
31
+ else:
32
+ self.gepa_proposer = None
33
+ self.model = self.config.get("model", "gpt-4o")
34
+ self.temperature = self.config.get("temperature", 0.7)
35
+
36
+ def propose_improved_prompt(
37
+ self,
38
+ current_prompt: str,
39
+ evaluation_results: dict[str, Any],
40
+ reflection: str,
41
+ component_name: str = "system_prompt",
42
+ ) -> str:
43
+ """
44
+ Propose an improved prompt based on evaluation results and reflection.
45
+
46
+ Args:
47
+ current_prompt: Current prompt text
48
+ evaluation_results: Evaluation results dictionary
49
+ reflection: Reflection markdown content
50
+ component_name: Name of the prompt component
51
+
52
+ Returns:
53
+ Proposed improved prompt text
54
+ """
55
+ # Build reflective dataset from evaluation results
56
+ reflective_data = self._build_reflective_dataset(evaluation_results)
57
+
58
+ # Use GEPA if enabled
59
+ if self.use_gepa and self.gepa_proposer:
60
+ return self.gepa_proposer.propose_improved_prompt(
61
+ current_prompt=current_prompt,
62
+ reflective_dataset=reflective_data,
63
+ component_name=component_name,
64
+ )
65
+
66
+ # Fallback to custom implementation
67
+ # Create proposal prompt
68
+ proposal_prompt = self._create_proposal_prompt(
69
+ current_prompt=current_prompt,
70
+ reflective_data=reflective_data,
71
+ reflection=reflection,
72
+ component_name=component_name,
73
+ )
74
+
75
+ # Get proposal from LLM
76
+ response = self.llm_client.chat_completion(
77
+ messages=[{"role": "user", "content": proposal_prompt}],
78
+ model=self.model,
79
+ temperature=self.temperature,
80
+ )
81
+
82
+ # Extract proposed prompt
83
+ proposed_prompt = self._extract_proposed_prompt(response, current_prompt)
84
+
85
+ return proposed_prompt
86
+
87
+ def _build_reflective_dataset(self, evaluation_results: dict[str, Any]) -> list[dict[str, Any]]:
88
+ """Build reflective dataset from evaluation results."""
89
+ dataset = []
90
+
91
+ behaviors = evaluation_results.get("behaviors", {})
92
+
93
+ for behavior_name, behavior_data in behaviors.items():
94
+ score = behavior_data.get("score", 0.0)
95
+ evidence = behavior_data.get("evidence", [])
96
+ scenario_results = behavior_data.get("scenario_results", [])
97
+
98
+ # Collect failure examples
99
+ if score < 0.7: # Focus on failures
100
+ for scenario_result in scenario_results:
101
+ behavior_result = scenario_result.get("behavior_result", {})
102
+ if not behavior_result.get("passed", True):
103
+ dataset.append(
104
+ {
105
+ "behavior": behavior_name,
106
+ "score": score,
107
+ "evidence": evidence[:3], # Limit evidence
108
+ "scenario": scenario_result.get("scenario", {}).get("prompt", ""),
109
+ }
110
+ )
111
+
112
+ return dataset
113
+
114
+ def _create_proposal_prompt(
115
+ self,
116
+ current_prompt: str,
117
+ reflective_data: list[dict[str, Any]],
118
+ reflection: str,
119
+ component_name: str,
120
+ ) -> str:
121
+ """Create prompt for LLM to propose improved prompt."""
122
+
123
+ # Format reflective data
124
+ failure_examples = []
125
+ for i, data in enumerate(reflective_data[:5], 1): # Limit to 5 examples
126
+ failure_examples.append(
127
+ f"Example {i}:\n"
128
+ f" Behavior: {data['behavior']}\n"
129
+ f" Score: {data['score']:.2f}\n"
130
+ f" Issues: {', '.join(data['evidence'][:2])}\n"
131
+ )
132
+
133
+ prompt = f"""You are optimizing a coding agent's prompt to improve its behavior.
134
+
135
+ Current {component_name}:
136
+ ```
137
+ {current_prompt}
138
+ ```
139
+
140
+ Evaluation Results Summary:
141
+ {reflection[:1000]}...
142
+
143
+ Specific Failure Examples:
144
+ {"".join(failure_examples)}
145
+
146
+ Based on the evaluation results and reflection above, propose an improved version of the {component_name} that addresses the identified issues.
147
+
148
+ The improved prompt should:
149
+ 1. Address the root causes identified in the reflection
150
+ 2. Include specific guidance to prevent the failures observed
151
+ 3. Maintain the original intent while adding necessary constraints
152
+ 4. Be clear, actionable, and specific
153
+
154
+ Provide ONLY the improved prompt text, without additional explanation or markdown formatting.
155
+ """
156
+
157
+ return prompt
158
+
159
+ def _extract_proposed_prompt(self, response: str, fallback: str) -> str:
160
+ """Extract proposed prompt from LLM response."""
161
+ # Try to extract code block
162
+ import re
163
+
164
+ # Look for code blocks
165
+ code_blocks = re.findall(r"```(?:.*)?\n(.*?)```", response, re.DOTALL)
166
+ if code_blocks:
167
+ return code_blocks[0].strip()
168
+
169
+ # Look for text between markers
170
+ if "Current" in response and "Improved" in response:
171
+ # Try to extract after "Improved" marker
172
+ improved_section = response.split("Improved")[-1]
173
+ # Take first substantial paragraph
174
+ lines = [l.strip() for l in improved_section.split("\n") if l.strip()]
175
+ if lines:
176
+ return "\n".join(lines[:10]) # Take first 10 non-empty lines
177
+
178
+ # Fallback: use response as-is, but clean it up
179
+ cleaned = response.strip()
180
+ # Remove common prefixes
181
+ for prefix in ["Improved prompt:", "Here's the improved prompt:", "Proposed prompt:"]:
182
+ if cleaned.startswith(prefix):
183
+ cleaned = cleaned[len(prefix) :].strip()
184
+
185
+ return cleaned if cleaned else fallback
@@ -0,0 +1,13 @@
1
+ """Linter integration for CodeOptiX - works without API keys."""
2
+
3
+ from codeoptix.linters.base import LinterIssue, LinterResult, Severity
4
+ from codeoptix.linters.language_detector import LanguageDetector
5
+ from codeoptix.linters.runner import LinterRunner
6
+
7
+ __all__ = [
8
+ "LanguageDetector",
9
+ "LinterIssue",
10
+ "LinterResult",
11
+ "LinterRunner",
12
+ "Severity",
13
+ ]