prompt-enhancer-cli 1.5.0__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.
- prompt_enhancer/__init__.py +2 -0
- prompt_enhancer/agents.py +205 -0
- prompt_enhancer/cli.py +930 -0
- prompt_enhancer/dashboard.py +380 -0
- prompt_enhancer/lint.py +140 -0
- prompt_enhancer/view.py +236 -0
- prompt_enhancer_cli-1.5.0.dist-info/METADATA +215 -0
- prompt_enhancer_cli-1.5.0.dist-info/RECORD +12 -0
- prompt_enhancer_cli-1.5.0.dist-info/WHEEL +5 -0
- prompt_enhancer_cli-1.5.0.dist-info/entry_points.txt +3 -0
- prompt_enhancer_cli-1.5.0.dist-info/licenses/LICENSE +21 -0
- prompt_enhancer_cli-1.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent backends for prompt-enhancer — delegate enhancement to existing coding agents.
|
|
3
|
+
|
|
4
|
+
Each backend takes a seed prompt and returns an enhanced version by shelling out
|
|
5
|
+
to the agent's CLI. No API key needed — uses the agent's existing configuration.
|
|
6
|
+
|
|
7
|
+
Supported agents:
|
|
8
|
+
claude — Claude Code (claude -p)
|
|
9
|
+
codex — Codex CLI (codex)
|
|
10
|
+
auggie — Auggie (auggie --print)
|
|
11
|
+
opencode — OpenCode (opencode --print)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import subprocess
|
|
15
|
+
import sys
|
|
16
|
+
import os
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
ENHANCEMENT_PROMPT_TEMPLATE = """Transform this rough idea into a 7-section system prompt for AI coding agents.
|
|
21
|
+
|
|
22
|
+
SECTIONS: ROLE → CONTEXT → BEHAVIORAL RULES → TECHNICAL GUIDELINES → OUTPUT FORMAT → PITFALLS/GUARDRAILS → EXAMPLES
|
|
23
|
+
|
|
24
|
+
RULES:
|
|
25
|
+
- Be concrete — reference actual tools, patterns, conventions
|
|
26
|
+
- Be actionable — rules translate directly into agent behavior
|
|
27
|
+
- Be concise — 2-4 bullets per section
|
|
28
|
+
- Include a "pro tip" at the end
|
|
29
|
+
- Output ONLY the system prompt markdown, start with "# System Prompt: <Role>"
|
|
30
|
+
|
|
31
|
+
## Rough idea
|
|
32
|
+
{seed}
|
|
33
|
+
|
|
34
|
+
## Output
|
|
35
|
+
# System Prompt:"""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _find_binary(names):
|
|
39
|
+
"""Find the first available binary from a list of names."""
|
|
40
|
+
for name in names:
|
|
41
|
+
# Check common locations
|
|
42
|
+
for prefix in ["", str(Path.home() / ".local/bin/"), str(Path.home() / ".nvm/versions/node/v26.1.0/bin/")]:
|
|
43
|
+
path = os.path.join(prefix, name)
|
|
44
|
+
if os.path.exists(path) and os.access(path, os.X_OK):
|
|
45
|
+
return path
|
|
46
|
+
# Try which
|
|
47
|
+
try:
|
|
48
|
+
result = subprocess.run(["which", name], capture_output=True, text=True, timeout=5)
|
|
49
|
+
if result.returncode == 0:
|
|
50
|
+
return result.stdout.strip()
|
|
51
|
+
except Exception:
|
|
52
|
+
pass
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def enhance_via_claude(seed, config=None):
|
|
57
|
+
"""Enhance via Claude Code."""
|
|
58
|
+
binary = _find_binary(["claude"])
|
|
59
|
+
if not binary:
|
|
60
|
+
raise RuntimeError("Claude Code not found. Install: npm install -g @anthropic-ai/claude-code")
|
|
61
|
+
|
|
62
|
+
prompt = ENHANCEMENT_PROMPT_TEMPLATE.format(seed=seed)
|
|
63
|
+
result = subprocess.run(
|
|
64
|
+
[binary, "-p", prompt],
|
|
65
|
+
capture_output=True, text=True, timeout=120,
|
|
66
|
+
env={**os.environ, "CLAUDE_CODE_HEADLESS": "1"}
|
|
67
|
+
)
|
|
68
|
+
if result.returncode != 0:
|
|
69
|
+
raise RuntimeError(f"Claude Code failed: {result.stderr[:200]}")
|
|
70
|
+
return result.stdout.strip()
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def enhance_via_codex(seed, config=None):
|
|
74
|
+
"""Enhance via Codex CLI."""
|
|
75
|
+
binary = _find_binary(["codex"])
|
|
76
|
+
if not binary:
|
|
77
|
+
raise RuntimeError("Codex not found. Install: npm install -g @openai/codex")
|
|
78
|
+
|
|
79
|
+
prompt = ENHANCEMENT_PROMPT_TEMPLATE.format(seed=seed)
|
|
80
|
+
result = subprocess.run(
|
|
81
|
+
[binary, prompt],
|
|
82
|
+
capture_output=True, text=True, timeout=120,
|
|
83
|
+
env={**os.environ}
|
|
84
|
+
)
|
|
85
|
+
if result.returncode != 0:
|
|
86
|
+
raise RuntimeError(f"Codex failed: {result.stderr[:200]}")
|
|
87
|
+
return result.stdout.strip()
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def enhance_via_auggie(seed, config=None):
|
|
91
|
+
"""Enhance via Auggie (Augment)."""
|
|
92
|
+
binary = _find_binary(["auggie"])
|
|
93
|
+
if not binary:
|
|
94
|
+
raise RuntimeError("Auggie not found. Install: npm install -g @augmentcode/auggie")
|
|
95
|
+
|
|
96
|
+
prompt = ENHANCEMENT_PROMPT_TEMPLATE.format(seed=seed)
|
|
97
|
+
result = subprocess.run(
|
|
98
|
+
[binary, "--print", prompt],
|
|
99
|
+
capture_output=True, text=True, timeout=120,
|
|
100
|
+
env={**os.environ}
|
|
101
|
+
)
|
|
102
|
+
if result.returncode != 0:
|
|
103
|
+
raise RuntimeError(f"Auggie failed: {result.stderr[:200]}")
|
|
104
|
+
|
|
105
|
+
output = result.stdout.strip()
|
|
106
|
+
# Strip Auggie's thinking/exploration prefix
|
|
107
|
+
if "🤖" in output:
|
|
108
|
+
output = output.split("🤖")[-1].strip()
|
|
109
|
+
# Strip ANSI escape codes
|
|
110
|
+
import re
|
|
111
|
+
output = re.sub(r'\x1b\[[0-9;]*[a-zA-Z]', '', output)
|
|
112
|
+
return output
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def enhance_via_opencode(seed, config=None):
|
|
116
|
+
"""Enhance via OpenCode."""
|
|
117
|
+
binary = _find_binary(["opencode"])
|
|
118
|
+
if not binary:
|
|
119
|
+
raise RuntimeError("OpenCode not found.")
|
|
120
|
+
|
|
121
|
+
prompt = ENHANCEMENT_PROMPT_TEMPLATE.format(seed=seed)
|
|
122
|
+
result = subprocess.run(
|
|
123
|
+
[binary, "--print", prompt],
|
|
124
|
+
capture_output=True, text=True, timeout=120,
|
|
125
|
+
env={**os.environ}
|
|
126
|
+
)
|
|
127
|
+
if result.returncode != 0:
|
|
128
|
+
raise RuntimeError(f"OpenCode failed: {result.stderr[:200]}")
|
|
129
|
+
return result.stdout.strip()
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# Map agent names to enhancers
|
|
133
|
+
AGENT_ENHANCERS = {
|
|
134
|
+
"claude": enhance_via_claude,
|
|
135
|
+
"codex": enhance_via_codex,
|
|
136
|
+
"auggie": enhance_via_auggie,
|
|
137
|
+
"opencode": enhance_via_opencode,
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
# Invocation recipes for running an arbitrary prompt through an agent CLI.
|
|
142
|
+
# Used by the blind-judge path so the benchmark judge can differ from the generator.
|
|
143
|
+
AGENT_INVOKERS = {
|
|
144
|
+
"claude": {"binary": "claude", "args": ["-p"], "env": {"CLAUDE_CODE_HEADLESS": "1"}},
|
|
145
|
+
"codex": {"binary": "codex", "args": [], "env": {}},
|
|
146
|
+
"auggie": {"binary": "auggie", "args": ["--print"], "env": {}},
|
|
147
|
+
"opencode": {"binary": "opencode", "args": ["--print"], "env": {}},
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def run_via_agent(prompt, via_agent, timeout=180):
|
|
152
|
+
"""Run a raw prompt through an agent CLI and return its stdout.
|
|
153
|
+
|
|
154
|
+
Unlike enhance_via_*, this passes the prompt verbatim — no enhancement
|
|
155
|
+
template wrapping. Used for blind judging in `pe benchmark --judge-via`.
|
|
156
|
+
"""
|
|
157
|
+
recipe = AGENT_INVOKERS.get(via_agent)
|
|
158
|
+
if not recipe:
|
|
159
|
+
raise RuntimeError(f"Unknown agent: {via_agent}. Supported: {', '.join(AGENT_INVOKERS.keys())}")
|
|
160
|
+
binary = _find_binary([recipe["binary"]])
|
|
161
|
+
if not binary:
|
|
162
|
+
raise RuntimeError(f"{via_agent} not found on PATH")
|
|
163
|
+
result = subprocess.run(
|
|
164
|
+
[binary, *recipe["args"], prompt],
|
|
165
|
+
capture_output=True, text=True, timeout=timeout,
|
|
166
|
+
env={**os.environ, **recipe["env"]},
|
|
167
|
+
)
|
|
168
|
+
if result.returncode != 0:
|
|
169
|
+
raise RuntimeError(f"{via_agent} failed: {result.stderr[:200]}")
|
|
170
|
+
output = result.stdout.strip()
|
|
171
|
+
if via_agent == "auggie":
|
|
172
|
+
if "🤖" in output:
|
|
173
|
+
output = output.split("🤖")[-1].strip()
|
|
174
|
+
import re
|
|
175
|
+
output = re.sub(r'\x1b\[[0-9;]*[a-zA-Z]', '', output)
|
|
176
|
+
return output
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def enhance(seed, via_agent=None, config=None):
|
|
180
|
+
"""Enhance a seed prompt. If via_agent is set, delegate to that agent.
|
|
181
|
+
Otherwise, use the API key (legacy path).
|
|
182
|
+
"""
|
|
183
|
+
if via_agent:
|
|
184
|
+
enhancer = AGENT_ENHANCERS.get(via_agent)
|
|
185
|
+
if not enhancer:
|
|
186
|
+
raise RuntimeError(f"Unknown agent: {via_agent}. Supported: {', '.join(AGENT_ENHANCERS.keys())}")
|
|
187
|
+
return enhancer(seed, config)
|
|
188
|
+
|
|
189
|
+
# Fall through to API-key mode — caller must handle
|
|
190
|
+
raise RuntimeError("No enhancement method available. Use --via <agent> or set LLM_API_KEY.")
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def get_available_agents():
|
|
194
|
+
"""Return list of agents with available binaries."""
|
|
195
|
+
available = []
|
|
196
|
+
for agent, enhancer in AGENT_ENHANCERS.items():
|
|
197
|
+
try:
|
|
198
|
+
binary = _find_binary([agent])
|
|
199
|
+
if binary:
|
|
200
|
+
available.append((agent, binary, "ready"))
|
|
201
|
+
else:
|
|
202
|
+
available.append((agent, None, "not found"))
|
|
203
|
+
except Exception:
|
|
204
|
+
available.append((agent, None, "error"))
|
|
205
|
+
return available
|