feat(ui): replace Reset example with an Example preset dropdown and a Clear button on the Decisions tab (#45848)

Backport of #45848 to rc/1.106.0.
Cherry-picked from dc77381956 (main).
This commit is contained in:
devin-ai-integration[bot] 2026-10-10 16:30:25 -07:00 • committed by mateo-berri
parent 7318f83976
commit ad4d9b1a92
4 changed files with 340 additions and 45 deletions

View file

@ -71,6 +71,12 @@ const selectEndpoint = async (endpoint: "/v1/decisions" | "/v1/systemone") => {
await userEvent.click(await screen.findByRole("option", { name: endpoint, exact: true }));
};
const selectPreset = async (label: string) => {
screen.getByRole("combobox", { name: "Example" }).focus();
await userEvent.keyboard("{ArrowDown}");
await userEvent.click(await screen.findByRole("option", { name: label }));
};
const createResponse = (body: SystemOneResponse | OpenAIDecisionsResponse, status = 200, errorText = "") =>
({
ok: status >= 200 && status < 300,
@ -99,20 +105,81 @@ describe("SystemOneUI integration", () => {
document.cookie = "token=; path=/; max-age=0";
});
it("restores the example after the request is edited", async () => {
const user = userEvent.setup();
it("switches between example presets and reads Custom once the request is edited", async () => {
render(<SystemOneUI accessToken="session-key" />);
const editor = await openJsonEditor();
const example = (editor as HTMLTextAreaElement).value;
const resetButton = screen.getByRole("button", { name: "Reset example" });
expect(resetButton).toBeDisabled();
const picker = screen.getByRole("combobox", { name: "Example" });
expect(picker).toHaveTextContent("Triage a bug report");
fireEvent.change(editor, { target: { value: "{}" } });
expect(resetButton).toBeEnabled();
await user.click(resetButton);
expect(picker).toHaveTextContent("Custom");
await selectPreset("Triage a bug report");
expect(editor).toHaveValue(example);
expect(resetButton).toBeDisabled();
expect(picker).toHaveTextContent("Triage a bug report");
await selectPreset("Score a sales lead");
expect(picker).toHaveTextContent("Score a sales lead");
expect(JSON.parse((editor as HTMLTextAreaElement).value)).toMatchObject({ questions: { fit: { type: "score" } } });
});
it("clears the whole request and lets a preset be picked from nothing", async () => {
const user = userEvent.setup();
render(<SystemOneUI accessToken="session-key" />);
const clear = screen.getByRole("button", { name: "Clear" });
expect(screen.getByRole("textbox", { name: "Input" })).toHaveDisplayValue(/streaming responses/);
await user.click(clear);
expect(screen.getByRole("textbox", { name: "Input" })).toHaveValue("");
expect(screen.queryAllByRole("group", { name: /Question / })).toHaveLength(0);
expect(screen.getByRole("button", { name: "Send" })).toBeDisabled();
expect(clear).toBeDisabled();
expect(screen.getByRole("combobox", { name: "Example" })).toHaveTextContent("Custom");
await selectPreset("Route a support ticket");
expect(screen.getByRole("textbox", { name: "Input" })).toHaveDisplayValue(/charged twice/);
expect(screen.getAllByRole("group", { name: /Question / })).toHaveLength(1);
expect(screen.getByRole("button", { name: "Send" })).toBeEnabled();
});
it("keeps the preset label after picking a model and leaves an omitted model out when clearing", async () => {
mockModelLookup.mockResolvedValue(modelGroupInfoResponse(DECISION_AND_CHAT_MODELS));
render(<SystemOneUI accessToken="session-key" />);
await waitFor(() => expect(screen.getByRole("combobox", { name: "Decision model" })).toHaveValue("jev-latest"));
const picker = screen.getByRole("combobox", { name: "Example" });
const editor = await openJsonEditor();
const example = JSON.parse((editor as HTMLTextAreaElement).value) as Record<string, unknown>;
const { model: _model, ...withoutModel } = example;
fireEvent.change(editor, {
target: { value: JSON.stringify({ ...withoutModel, model: "pplx-decider" }, null, 2) },
});
expect(picker).toHaveTextContent("Triage a bug report");
fireEvent.change(editor, { target: { value: JSON.stringify(withoutModel, null, 2) } });
expect(picker).toHaveTextContent("Triage a bug report");
await userEvent.click(screen.getByRole("button", { name: "Clear" }));
expect(JSON.parse((editor as HTMLTextAreaElement).value)).toEqual({ state: "", questions: {} });
await selectPreset("Score a sales lead");
expect(JSON.parse((editor as HTMLTextAreaElement).value)).not.toHaveProperty("model");
});
it("offers the same presets on /v1/decisions in the OpenAI shape and clears to an empty input", async () => {
const user = userEvent.setup();
render(<SystemOneUI accessToken="session-key" />);
await selectEndpoint("/v1/decisions");
await selectPreset("Moderate a forum comment");
await user.click(screen.getByRole("tab", { name: "JSON" }));
const editor = screen.getByRole("textbox", { name: "Decisions JSON payload" }) as HTMLTextAreaElement;
const payload = JSON.parse(editor.value);
expect(payload.input).toMatch(/stream=false/);
expect(payload.questions).toEqual([
{ type: "predicate", name: "breaks_rules", instructions: "Does this comment break the community guidelines?" },
]);
await user.click(screen.getByRole("button", { name: "Clear" }));
expect(JSON.parse(editor.value)).toEqual({ input: "", questions: [] });
expect(screen.getByRole("button", { name: "Send" })).toBeDisabled();
});
it("offers both literal proxy endpoints without TypeSafe or product prefixes", async () => {
@ -227,7 +294,7 @@ describe("SystemOneUI integration", () => {
await selectEndpoint("/v1/decisions");
expect(screen.getByRole("textbox", { name: "Decisions JSON payload" })).toHaveValue(JSON.stringify(payload));
await user.click(screen.getByRole("button", { name: "Reset example" }));
await selectPreset("Triage a bug report");
expect(screen.getByRole("textbox", { name: "Decisions JSON payload" })).toHaveValue(nativeExample);
await selectEndpoint("/v1/systemone");
expect(screen.getByRole("textbox", { name: "System One JSON payload" })).toHaveValue(systemOneDraft);
@ -403,7 +470,7 @@ describe("SystemOneUI integration", () => {
);
expect(next).toEqual({ ...payload, questions: [{ ...payload.questions[0], instructions: "Is it urgent?" }] });
await user.click(screen.getByRole("tab", { name: "Form" }));
await user.click(screen.getByRole("button", { name: "Reset example" }));
await selectPreset("Triage a bug report");
expect(screen.getByRole("textbox", { name: "Input" })).toBeInTheDocument();
expect(screen.getAllByRole("group", { name: /Question \d/ })).toHaveLength(3);
await selectEndpoint("/v1/systemone");

View file

@ -9,10 +9,10 @@ import { SearchSelect } from "@/components/shared/SearchSelect";
import { DECISIONS_DOCS_URL } from "@/lib/decisionModels";
import { uiHref } from "@/utils/uiHref";
import { useMutation } from "@tanstack/react-query";
import { Code, Info, LoaderCircle, RotateCcw, Send } from "lucide-react";
import { Code, Eraser, Info, LoaderCircle, Send } from "lucide-react";
import { useEffect, useMemo, useRef, useState } from "react";
import { makePlaygroundDecisionRequest, type PlaygroundDecisionRequest } from "../../llm_calls/system_one";
import { decisionsExample, openAIDecisionsExample } from "./lib/example";
import { DECISION_PRESETS, emptyPayload, matchPreset, presetPayload, type DecisionPreset } from "./lib/example";
import { payloadModel, withPayloadModel } from "./lib/payloadModel";
import JsonEditor from "./JsonEditor";
import QuestionBreakdown from "./QuestionBreakdown";
@ -35,8 +35,36 @@ interface SystemOneSendVariables {
signal: AbortSignal;
}
const CUSTOM_PRESET = "custom";
const DECISION_MODELS_DISCUSSION_URL = "https://github.com/BerriAI/litellm/discussions/44231";
interface PresetPickerProps {
activePreset: DecisionPreset | undefined;
onPick: (id: string | null) => void;
}
function PresetPicker({ activePreset, onPick }: PresetPickerProps) {
return (
<Select value={activePreset?.id ?? CUSTOM_PRESET} onValueChange={onPick}>
<SelectTrigger className="w-56" aria-label="Example">
<SelectValue>{activePreset?.label ?? "Custom"}</SelectValue>
</SelectTrigger>
<SelectContent>
{activePreset === undefined && (
<SelectItem value={CUSTOM_PRESET} disabled>
Custom
</SelectItem>
)}
{DECISION_PRESETS.map((preset) => (
<SelectItem key={preset.id} value={preset.id}>
{preset.label}
</SelectItem>
))}
</SelectContent>
</Select>
);
}
function getCustomProxyBaseUrl(): string | undefined {
return typeof window === "undefined" ? undefined : window.sessionStorage.getItem("customProxyBaseUrl") || undefined;
}
@ -53,9 +81,10 @@ export default function SystemOneUI({ accessToken, disabledPersonalKeyCreation =
const [endpoint, setEndpoint] = useState<PlaygroundDecisionRequest["endpoint"]>("/v1/systemone");
const [drafts, setDrafts] = useState<Partial<Record<PlaygroundDecisionRequest["endpoint"], string>>>({});
const [view, setView] = useState<EditorView>("form");
const example = endpoint === "/v1/decisions" ? openAIDecisionsExample : decisionsExample;
const examplePayload = JSON.stringify(example(decisionModels[0]), null, 2);
const rawPayload = drafts[endpoint] ?? examplePayload;
const rawPayload = drafts[endpoint] ?? presetPayload(DECISION_PRESETS[0], endpoint, decisionModels[0]);
const draftModel = drafts[endpoint] === undefined ? decisionModels[0] : payloadModel(rawPayload);
const activePreset = matchPreset(endpoint, rawPayload);
const clearedPayload = emptyPayload(endpoint, draftModel);
const activeController = useRef<AbortController | null>(null);
const validated = useMemo(
() =>
@ -95,9 +124,11 @@ export default function SystemOneUI({ accessToken, disabledPersonalKeyCreation =
}
}
function handleResetExample() {
clearRequestState();
setDrafts((current) => Object.fromEntries(Object.entries(current).filter(([key]) => key !== endpoint)));
function handlePresetPick(id: string | null) {
const preset = DECISION_PRESETS.find((candidate) => candidate.id === id);
if (preset !== undefined) {
handlePayloadChange(presetPayload(preset, endpoint, draftModel));
}
}
function handleModelPick(model: string | null) {
@ -204,9 +235,14 @@ export default function SystemOneUI({ accessToken, disabledPersonalKeyCreation =
)}
</div>
<div className="ml-auto flex items-center gap-2">
<Button variant="outline" onClick={handleResetExample} disabled={rawPayload === examplePayload}>
<RotateCcw />
Reset example
<PresetPicker activePreset={activePreset} onPick={handlePresetPick} />
<Button
variant="outline"
onClick={() => handlePayloadChange(clearedPayload)}
disabled={rawPayload === clearedPayload}
>
<Eraser />
Clear
</Button>
{view === "json" && (
<Button variant="outline" onClick={handleFormatJson} disabled={!rawPayload.trim() || hasSyntaxError}>

View file

@ -0,0 +1,60 @@
import { describe, expect, it } from "vitest";
import {
DECISION_PRESETS,
emptyPayload,
openAIDecisionsExample,
presetPayload,
toOpenAIDecisionsRequest,
matchPreset,
} from "./example";
import { validateOpenAIDecisionsPayload, validateSystemOnePayload } from "./validatePayload";
describe("decision presets", () => {
it.each(DECISION_PRESETS.map((preset) => [preset.label, preset] as const))(
"%s is a valid request on both endpoints",
(_label, preset) => {
expect(
validateSystemOnePayload(presetPayload(preset, "/v1/systemone", "jev-latest"), "/v1/systemone"),
).toMatchObject({ isValid: true, issues: [] });
expect(validateOpenAIDecisionsPayload(presetPayload(preset, "/v1/decisions", "jev-latest"))).toMatchObject({
isValid: true,
issues: [],
});
},
);
it("covers every question type across the presets", () => {
const types = new Set(
DECISION_PRESETS.flatMap((preset) => Object.values(preset.request.questions).map((question) => question.type)),
);
expect([...types].sort()).toEqual(["choice", "noul", "score"]);
});
it("maps System One questions onto the OpenAI shape by name", () => {
const request = toOpenAIDecisionsRequest(DECISION_PRESETS[0].request, "jev-latest");
expect(request.questions.map((question) => [question.type, question.name])).toEqual([
["choice", "area"],
["predicate", "has_repro_steps"],
["score", "severity"],
]);
expect(request).toEqual(openAIDecisionsExample("jev-latest"));
});
it("recognises a preset whatever the model key holds or where it sits", () => {
const lead = DECISION_PRESETS.find((preset) => preset.id === "lead-scoring");
const parsed = JSON.parse(presetPayload(lead!, "/v1/systemone", "jev-latest")) as Record<string, unknown>;
const { model: _model, ...rest } = parsed;
expect(matchPreset("/v1/systemone", JSON.stringify({ ...rest, model: "pplx-decider" }))).toBe(lead);
expect(matchPreset("/v1/systemone", JSON.stringify(rest))).toBe(lead);
expect(matchPreset("/v1/decisions", presetPayload(lead!, "/v1/decisions"))).toBe(lead);
expect(matchPreset("/v1/decisions", presetPayload(lead!, "/v1/systemone"))).toBeUndefined();
expect(matchPreset("/v1/systemone", JSON.stringify({ ...rest, state: "edited" }))).toBeUndefined();
expect(matchPreset("/v1/systemone", "{")).toBeUndefined();
});
it("omits the model from payloads when none is known", () => {
expect(JSON.parse(presetPayload(DECISION_PRESETS[1], "/v1/systemone"))).not.toHaveProperty("model");
expect(JSON.parse(emptyPayload("/v1/decisions"))).toEqual({ input: "", questions: [] });
expect(validateSystemOnePayload(emptyPayload("/v1/systemone"), "/v1/systemone").isValid).toBe(false);
});
});

View file

@ -1,5 +1,39 @@
import type { DecisionRequest, SystemOneRequest } from "./schemas";
import type { OpenAIDecisionsRequest } from "./openAIDecisions";
import { parseJson } from "./validatePayload";
type PresetChoice = {
type: "choice";
instructions: string;
criteria: Record<string, string>;
};
type PresetNoul = {
type: "noul";
instructions: string;
criteria?: { true: string; false: string };
};
type PresetScore = {
type: "score";
instructions: string;
criteria: string[];
};
export type PresetQuestion = PresetChoice | PresetNoul | PresetScore;
export type PresetRequest = {
state: string;
questions: Record<string, PresetQuestion>;
};
type PresetEndpoint = "/v1/decisions" | "/v1/systemone";
export interface DecisionPreset {
id: string;
label: string;
request: PresetRequest;
}
export const SYSTEM_ONE_EXAMPLE = {
model: "jev-latest",
@ -38,34 +72,132 @@ export const SYSTEM_ONE_EXAMPLE = {
},
} satisfies SystemOneRequest;
export const decisionsExample = (model?: string): DecisionRequest => ({ ...SYSTEM_ONE_EXAMPLE, model });
const { model: _exampleModel, ...bugTriage }: SystemOneRequest & PresetRequest = SYSTEM_ONE_EXAMPLE;
export const openAIDecisionsExample = (model?: string): OpenAIDecisionsRequest => ({
model,
input: SYSTEM_ONE_EXAMPLE.state,
questions: [
{
const supportRouting = {
state:
"Hi, I was charged twice for my team plan this month and the second charge pushed my card over its limit. I need the duplicate refunded today and want to know why it happened.",
questions: {
department: {
type: "choice",
name: "area",
instructions: SYSTEM_ONE_EXAMPLE.questions.area.instructions,
choices: Object.entries(SYSTEM_ONE_EXAMPLE.questions.area.criteria).map(([value, description]) => ({
value,
description,
})),
instructions: "Which team should handle this ticket?",
criteria: {
billing: "Invoices, charges, refunds, and plan changes",
technical: "Bugs, errors, outages, and integration help",
account: "Login, permissions, and profile settings",
sales: "Pricing questions and new purchases",
},
},
{
type: "predicate",
name: "has_repro_steps",
instructions: SYSTEM_ONE_EXAMPLE.questions.has_repro_steps.instructions,
},
} satisfies PresetRequest;
const moderation = {
state:
"This guide is garbage and whoever wrote it should be fired. The fix that actually works is setting stream=false, took me two days to figure that out.",
questions: {
breaks_rules: {
type: "noul",
instructions: "Does this comment break the community guidelines?",
criteria: {
true: "Insults, harassment, slurs, or threats aimed at a person",
false: "Blunt or frustrated but still about the content",
},
},
{
},
} satisfies PresetRequest;
const leadScoring = {
state:
"Inbound form: VP Engineering at a 400 person fintech. Running a self hosted gateway today, evaluating replacements this quarter, budget approved, needs SSO and audit logs.",
questions: {
fit: {
type: "score",
name: "severity",
instructions: SYSTEM_ONE_EXAMPLE.questions.severity.instructions,
levels: SYSTEM_ONE_EXAMPLE.questions.severity.criteria.map((description, index) => ({
label: String(index),
description,
})),
instructions: "How well does this lead fit our ideal customer?",
criteria: [
"No fit, wrong market or no budget",
"Weak fit, early curiosity only",
"Possible fit, needs discovery",
"Strong fit, active evaluation",
"Ideal fit, ready to buy this quarter",
],
},
],
},
} satisfies PresetRequest;
export const DECISION_PRESETS: readonly DecisionPreset[] = [
{ id: "bug-triage", label: "Triage a bug report", request: bugTriage },
{ id: "support-routing", label: "Route a support ticket", request: supportRouting },
{ id: "moderation", label: "Moderate a forum comment", request: moderation },
{ id: "lead-scoring", label: "Score a sales lead", request: leadScoring },
];
const toOpenAIQuestion = (name: string, question: PresetQuestion): OpenAIDecisionsRequest["questions"][number] => {
switch (question.type) {
case "choice":
return {
type: "choice",
name,
instructions: question.instructions,
choices: Object.entries(question.criteria).map(([value, description]) => ({ value, description })),
};
case "noul":
return { type: "predicate", name, instructions: question.instructions };
case "score":
return {
type: "score",
name,
instructions: question.instructions,
levels: question.criteria.map((description, index) => ({ label: String(index), description })),
};
}
};
export const toSystemOneRequest = (request: PresetRequest, model?: string): DecisionRequest => ({ model, ...request });
export const toOpenAIDecisionsRequest = (request: PresetRequest, model?: string): OpenAIDecisionsRequest => ({
model,
input: request.state,
questions: Object.entries(request.questions).map(([name, question]) => toOpenAIQuestion(name, question)),
});
export const presetPayload = (preset: DecisionPreset, endpoint: PresetEndpoint, model?: string): string =>
JSON.stringify(
endpoint === "/v1/decisions"
? toOpenAIDecisionsRequest(preset.request, model)
: toSystemOneRequest(preset.request, model),
null,
2,
);
const stableJson = (value: unknown): string =>
JSON.stringify(value, (_key, item: unknown) =>
item !== null && typeof item === "object" && !Array.isArray(item)
? Object.fromEntries(Object.entries(item as Record<string, unknown>).sort(([a], [b]) => a.localeCompare(b)))
: item,
);
const withoutModel = (value: unknown): string => {
const { model: _model, ...rest } = (value ?? {}) as Record<string, unknown>;
return stableJson(rest);
};
export const matchPreset = (endpoint: PresetEndpoint, raw: string): DecisionPreset | undefined => {
const json = parseJson(raw);
if (!json.ok) {
return undefined;
}
const current = withoutModel(json.value);
return DECISION_PRESETS.find((preset) => withoutModel(JSON.parse(presetPayload(preset, endpoint))) === current);
};
export const emptyPayload = (endpoint: PresetEndpoint, model?: string): string =>
JSON.stringify(
endpoint === "/v1/decisions" ? { model, input: "", questions: [] } : { model, state: "", questions: {} },
null,
2,
);
export const decisionsExample = (model?: string): DecisionRequest => toSystemOneRequest(bugTriage, model);
export const openAIDecisionsExample = (model?: string): OpenAIDecisionsRequest =>
toOpenAIDecisionsRequest(bugTriage, model);