Skip to content
31 changes: 12 additions & 19 deletions app/(main)/configurations/prompt-editor/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,8 @@
import { invalidateConfigCache } from "@/app/lib/utils";
import { configState } from "@/app/lib/store/configStore";
import { apiFetch } from "@/app/lib/apiClient";

const DEFAULT_CONFIG: ConfigBlob = {
completion: {
provider: "openai",
type: "text",
params: {
model: "gpt-4o-mini",
instructions: "",
temperature: 0.7,
tools: [],
},
},
};
import { isGpt5Model } from "@/app/lib/models";
import { DEFAULT_CONFIG } from "@/app/lib/constants";

function PromptEditorContent() {
const toast = useToast();
Expand All @@ -55,7 +44,6 @@
const urlDatasetId = searchParams.get("dataset");
const urlExperimentName = searchParams.get("experiment");
const fromEvaluations = searchParams.get("from") === "evaluations";

const {
configs: savedConfigs,
isLoading,
Expand All @@ -78,10 +66,10 @@
const [currentConfigBlob, setCurrentConfigBlob] =
useState<ConfigBlob>(DEFAULT_CONFIG);
const [currentConfigName, setCurrentConfigName] = useState<string>("");
const [selectedConfigId, setSelectedConfigId] = useState<string>(""); // Selected version ID
const [selectedConfigId, setSelectedConfigId] = useState<string>("");
const [currentConfigParentId, setCurrentConfigParentId] =
useState<string>("");
const [currentConfigVersion, setCurrentConfigVersion] = useState<number>(0); // Version number for evaluation
const [currentConfigVersion, setCurrentConfigVersion] = useState<number>(0);
const [provider, setProvider] = useState<string>("openai");
const [temperature, setTemperature] = useState<number>(0.7);
const [tools, setTools] = useState<Tool[]>([]);
Expand Down Expand Up @@ -135,7 +123,7 @@
);
if (selectInHistory) setSelectedVersion(config);
},
[],

Check warning on line 126 in app/(main)/configurations/prompt-editor/page.tsx

View workflow job for this annotation

GitHub Actions / lint-and-build

React Hook React.useCallback has a missing dependency: 'currentConfigParentId'. Either include it or remove the dependency array. You can also replace multiple useState variables with useReducer if 'setExpandedConfigs' needs the current value of 'currentConfigParentId'
);

const handleLoadConfig = React.useCallback(
Expand All @@ -156,7 +144,7 @@
loadVersionsForConfig(config.config_id);
applyConfig(config);
},
[applyConfig, loadVersionsForConfig, DEFAULT_CONFIG],

Check warning on line 147 in app/(main)/configurations/prompt-editor/page.tsx

View workflow job for this annotation

GitHub Actions / lint-and-build

React Hook React.useCallback has an unnecessary dependency: 'DEFAULT_CONFIG'. Either exclude it or remove the dependency array. Outer scope values like 'DEFAULT_CONFIG' aren't valid dependencies because mutating them doesn't re-render the component
);

// Initialize editor from URL params — runs once, on first load completion
Expand Down Expand Up @@ -202,7 +190,7 @@
if (config) applyConfig(config, showHistory);
setEditorReady(true);
})();
}, [

Check warning on line 193 in app/(main)/configurations/prompt-editor/page.tsx

View workflow job for this annotation

GitHub Actions / lint-and-build

React Hook useEffect has an unnecessary dependency: 'DEFAULT_CONFIG'. Either exclude it or remove the dependency array. Outer scope values like 'DEFAULT_CONFIG' aren't valid dependencies because mutating them doesn't re-render the component
initialLoadComplete,
urlConfigId,
urlVersion,
Expand Down Expand Up @@ -287,17 +275,22 @@
}
});

const model = currentConfigBlob.completion.params.model;
const gpt5 = isGpt5Model(model);

const configBlob: ConfigBlob = {
completion: {
provider: currentConfigBlob.completion.provider,
type: currentConfigBlob.completion.type || "text",
params: {
model: currentConfigBlob.completion.params.model,
model,
instructions: currentContent,
temperature: currentConfigBlob.completion.params.temperature,
...(!gpt5 && {
temperature: currentConfigBlob.completion.params.temperature,
}),
...(allKnowledgeBaseIds.length > 0 && {
knowledge_base_ids: allKnowledgeBaseIds,
max_num_results: maxNumResults,
...(!gpt5 && { max_num_results: maxNumResults }),
}),
},
},
Expand Down
84 changes: 29 additions & 55 deletions app/(main)/evaluations/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import {
GroupedTraceItem,
isGroupedFormat,
} from "@/app/components/types";
import { getStatusColor } from "@/app/components/utils";
import ConfigModal from "@/app/components/ConfigModal";
import Sidebar from "@/app/components/Sidebar";
import DetailedResultsTable from "@/app/components/DetailedResultsTable";
Expand All @@ -35,6 +34,7 @@ import {
GroupIcon,
RefreshIcon,
} from "@/app/components/icons";
import { sanitizeCSVCell } from "@/app/lib/utils";

export default function EvaluationReport() {
const router = useRouter();
Expand All @@ -56,23 +56,6 @@ export default function EvaluationReport() {
const [isResyncing, setIsResyncing] = useState(false);
const [showNoTracesModal, setShowNoTracesModal] = useState(false);

// CSV helper functions
const escapeCSVValue = (value: string): string => {
return value.replace(/"/g, '""').replace(/\n/g, " ");
};

const sanitizeCSVCell = (
value: string,
preventFormulaInjection = false,
): string => {
let sanitized = escapeCSVValue(value);
// Prevent CSV formula injection by prepending space to values starting with =, +, -, @
if (preventFormulaInjection && /^[=+\-@]/.test(sanitized)) {
sanitized = " " + sanitized;
}
return `"${sanitized}"`;
};

useEffect(() => {
if (apiKeys.length > 0 && !selectedKeyId) {
setSelectedKeyId(apiKeys[0].id);
Expand Down Expand Up @@ -394,12 +377,14 @@ export default function EvaluationReport() {

const scoreObject = getScoreObject(job);
const hasScore = !!scoreObject;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const statusColor = getStatusColor(job.status);
const isNewFormat = hasSummaryScores(scoreObject);
const summaryScores =
isNewFormat && scoreObject ? scoreObject.summary_scores || [] : [];

const isJobInProgress =
job.status.toLowerCase() !== "completed" &&
job.status.toLowerCase() !== "failed";

return (
<div
className="w-full h-screen flex flex-col"
Expand Down Expand Up @@ -565,26 +550,25 @@ export default function EvaluationReport() {
</div>
</div>

{/* Content */}
<div
className="flex-1 overflow-auto p-6"
style={{ backgroundColor: colors.bg.secondary }}
>
<div className="max-w-7xl mx-auto space-y-6">
{/* Metrics */}
{hasScore && isNewFormat ? (
<div>
{summaryScores.some(
(s) => job.total_items && s.total_pairs < job.total_items,
) && (
<div className="flex items-center gap-2 px-3 py-2 rounded-lg mb-3 text-xs bg-amber-500/10 border border-amber-500/30 text-status-warning">
<WarningTriangleIcon className="flex-shrink-0" />
Some traces are still being scored. Scores shown are
partial and may change — click{" "}
<strong className="font-semibold mx-1">Resync</strong> to
get the latest.
</div>
)}
) &&
isJobInProgress && (
<div className="flex items-center gap-2 px-3 py-2 rounded-lg mb-3 text-xs bg-amber-500/10 border border-amber-500/30 text-status-warning">
<WarningTriangleIcon className="shrink-0" />
Some traces are still being scored. Scores shown are
partial and may change - click{" "}
<strong className="font-semibold">Resync</strong> to get
the latest.
</div>
)}
<div className="flex items-center justify-between mb-3">
<h3
className="text-sm font-semibold"
Expand Down Expand Up @@ -636,18 +620,13 @@ export default function EvaluationReport() {
>
{summary.std !== undefined &&
`±${summary.std.toFixed(3)} · `}
{job.total_items &&
summary.total_pairs < job.total_items ? (
<span
className="inline-flex items-center gap-1 font-medium text-status-warning"
title={`Only ${summary.total_pairs} of ${job.total_items} traces scored — resync to update`}
>
{summary.total_pairs}/{job.total_items} pairs
<WarningTriangleIcon className="w-3 h-3" />
</span>
) : (
<span>{summary.total_pairs} pairs</span>
)}
<span>
{summary.total_pairs}
{job.total_items &&
summary.total_pairs < job.total_items &&
`/${job.total_items}`}{" "}
pairs
</span>
</div>
</div>
))}
Expand Down Expand Up @@ -686,18 +665,13 @@ export default function EvaluationReport() {
)}
</div>
<div className="text-xs mt-2 text-center text-text-secondary">
{job.total_items &&
summary.total_pairs < job.total_items ? (
<span
className="inline-flex items-center gap-1 font-medium text-status-warning"
title={`Only ${summary.total_pairs} of ${job.total_items} traces scored — resync to update`}
>
{summary.total_pairs}/{job.total_items} pairs
<WarningTriangleIcon className="w-3 h-3" />
</span>
) : (
<span>{summary.total_pairs} pairs</span>
)}
<span>
{summary.total_pairs}
{job.total_items &&
summary.total_pairs < job.total_items &&
`/${job.total_items}`}{" "}
pairs
</span>
</div>
</div>
))}
Expand Down
Loading
Loading