Skip to content

Commit f860569

Browse files
Steven GawthorpeSteven Gawthorpe
authored andcommitted
feat(web): iterate on a result
"Iterate on this" on the Optimized Prompt card makes the result the starting prompt for another run, keeping the method and dataset, with a banner naming the source session; the follow-up session is named "Iteration of <source>". Chaining runs, for example GEPA after a meta-prompt rewrite, no longer needs copy and paste.
1 parent 57142ef commit f860569

3 files changed

Lines changed: 57 additions & 1 deletion

File tree

API/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
### Added
11+
- **Iterate on a result** (web): a button on the Optimized Prompt card makes the
12+
result the starting prompt for another run, keeping the method and dataset;
13+
the new session is named "Iteration of <source>".
1114
- `POST /sessions/{id}/try`: run the session's original and/or optimized
1215
prompt on one input with the session's model and get both answers, the
1316
exact text sent, timing and any per-prompt error. A prompt with an

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ Without a dataset the score is a structural heuristic (length, sections, example
7474

7575
Whatever the score, the **Try it** card under the result runs the original and the optimized prompt on an input you type, with the same model, and shows both answers side by side with timing. After a measured run it can pick a held-out sample for you and says whether each answer matched the expected output.
7676

77+
**Iterate on this** makes a result the starting prompt for the next run, method and dataset kept, so you can follow a Meta-Prompt rewrite with GEPA, or evolve twice. The follow-up session is named after the one it came from.
78+
7779
#### Example 2: measuring against a dataset
7880

7981
A dataset is a list of **inputs** and the **outputs** you expect for them. The prompt you optimize is the *instruction* that should turn one input into its output; the app appends each input to your prompt where `{input}` goes, runs it, and compares the answer with the expected output.

Web/components/optimization-dashboard.tsx

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ import {
3232
Play,
3333
Pause,
3434
RotateCcw,
35+
Repeat,
36+
X,
3537
Download,
3638
Settings,
3739
Zap,
@@ -189,6 +191,9 @@ export function OptimizationDashboard() {
189191
const [selectedMethod, setSelectedMethod] = useState<OptimizationMethod>("meta_prompt")
190192
const [lastResult, setLastResult] = useState<OptimizeResponse["optimization_details"] | null>(null)
191193
const [lastSessionId, setLastSessionId] = useState<string | null>(null)
194+
const [lastSessionName, setLastSessionName] = useState<string | null>(null)
195+
// Set when the prompt box was filled from a previous result ("Iterate on this").
196+
const [iterationOf, setIterationOf] = useState<{ id: string; name: string } | null>(null)
192197
const [feedback, setFeedback] = useState<FeedbackRating | null>(null)
193198
const [feedbackComment, setFeedbackComment] = useState("")
194199
const [commentOpen, setCommentOpen] = useState(false)
@@ -438,7 +443,7 @@ export function OptimizationDashboard() {
438443
// Create a new session
439444
const providerInfo = providerData[selectedProvider]
440445
const session = await createSession({
441-
name: `Optimization ${new Date().toLocaleTimeString()}`,
446+
name: iterationOf ? `Iteration of ${iterationOf.name}` : `Optimization ${new Date().toLocaleTimeString()}`,
442447
original_prompt: originalPrompt,
443448
provider: providerInfo?.id || selectedProvider.toLowerCase(),
444449
model: selectedModel,
@@ -473,6 +478,8 @@ export function OptimizationDashboard() {
473478
setOptimizedPrompt(result.session.optimized_prompt)
474479
setLastResult(result.optimization_details)
475480
setLastSessionId(result.session.id)
481+
setLastSessionName(result.session.name)
482+
setIterationOf(null)
476483
setFeedback(null)
477484
setFeedbackComment("")
478485
setCommentOpen(false)
@@ -597,6 +604,28 @@ export function OptimizationDashboard() {
597604
setLastResult(null)
598605
setOptimizationProgress(0)
599606
setIsOptimizing(false)
607+
setIterationOf(null)
608+
}
609+
610+
// Use the current result as the starting point of the next run. Method and
611+
// dataset selections are kept so GEPA can follow a meta-prompt rewrite, for
612+
// example; the new session is named after the one it came from.
613+
const handleIterate = () => {
614+
if (!optimizedPrompt) return
615+
setIterationOf(lastSessionId ? { id: lastSessionId, name: lastSessionName ?? "previous result" } : null)
616+
setOriginalPrompt(optimizedPrompt)
617+
setOptimizedPrompt("")
618+
setLastResult(null)
619+
setLastSessionId(null)
620+
setFeedback(null)
621+
setCommentOpen(false)
622+
window.scrollTo({ top: 0, behavior: "smooth" })
623+
textareaRef.current?.focus()
624+
toast({
625+
title: "Ready to iterate",
626+
description: "The optimized prompt is now the starting point. Adjust the method or dataset, then optimize again.",
627+
duration: 4000,
628+
})
600629
}
601630

602631
// Requests from the sidebar: load a prompt file, start fresh, or reopen a session.
@@ -624,6 +653,7 @@ export function OptimizationDashboard() {
624653
setOriginalPrompt(session.original_prompt)
625654
setOptimizedPrompt(session.optimized_prompt ?? "")
626655
setLastSessionId(session.id)
656+
setLastSessionName(session.name)
627657
setFeedback(session.feedback_rating)
628658
setFeedbackComment(session.feedback_comment ?? "")
629659
setCommentOpen(false)
@@ -771,6 +801,15 @@ export function OptimizationDashboard() {
771801
</div>
772802
<div className="flex justify-between text-xs text-muted-foreground">
773803
<span>{originalPrompt.length} characters</span>
804+
{iterationOf && (
805+
<span className="ml-3 inline-flex items-center gap-1 rounded-full border border-orange-500/40 bg-orange-500/10 px-2 py-0.5 text-[11px] text-foreground">
806+
<Repeat className="w-3 h-3 text-orange-500" />
807+
Iterating on &ldquo;{iterationOf.name}&rdquo;
808+
<button type="button" className="ml-1 opacity-70 hover:opacity-100" onClick={() => setIterationOf(null)} aria-label="Stop iterating">
809+
<X className="w-3 h-3" />
810+
</button>
811+
</span>
812+
)}
774813
</div>
775814
</div>
776815

@@ -1486,6 +1525,18 @@ export function OptimizationDashboard() {
14861525
<p className="text-xs">Share optimization results</p>
14871526
</TooltipContent>
14881527
</Tooltip>
1528+
1529+
<Tooltip>
1530+
<TooltipTrigger asChild>
1531+
<Button variant="outline" size="sm" className="font-sans bg-transparent" onClick={handleIterate}>
1532+
<Repeat className="w-4 h-4" />
1533+
Iterate on this
1534+
</Button>
1535+
</TooltipTrigger>
1536+
<TooltipContent>
1537+
<p className="text-xs max-w-xs">Make this result the starting prompt for another run, keeping the method and dataset. For example, GEPA after a Meta-Prompt rewrite.</p>
1538+
</TooltipContent>
1539+
</Tooltip>
14891540
</>
14901541
}
14911542
/>

0 commit comments

Comments
 (0)