fix(ui): send the Decisions cURL under the configured auth header and preview the validated payload

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
mateo 2026-10-11 05:28:35 +00:00
parent 306cf9e654
commit 985cadfcaf
4 changed files with 72 additions and 8 deletions

View file

@ -8,7 +8,7 @@ import { SimpleTooltip } from "@/components/ui/tooltip";
import { SearchSelect } from "@/components/shared/SearchSelect";
import { cn } from "@/lib/cva.config";
import { DECISIONS_DOCS_URL } from "@/lib/decisionModels";
import { getProxyBaseUrl } from "@/components/networking";
import { getGlobalLitellmHeaderName, getProxyBaseUrl } from "@/components/networking";
import { uiHref } from "@/utils/uiHref";
import { useMutation } from "@tanstack/react-query";
import { BookOpen, Eraser, LoaderCircle, Send } from "lucide-react";
@ -118,6 +118,10 @@ export default function SystemOneUI({ accessToken, disabledPersonalKeyCreation =
systemOne.reset();
}
function handleReset() {
handlePayloadChange(presetPayload(DECISION_PRESETS[0], endpoint, draftModel ?? decisionModels[0]));
}
function handlePayloadChange(value: string) {
if (value !== rawPayload) {
clearRequestState();
@ -260,14 +264,14 @@ export default function SystemOneUI({ accessToken, disabledPersonalKeyCreation =
value={rawPayload}
onChange={handlePayloadChange}
validation={validated.validation}
onReset={() => handlePayloadChange(presetPayload(DECISION_PRESETS[0], endpoint, draftModel))}
onReset={handleReset}
/>
) : (
<SystemOneForm
value={rawPayload}
onChange={handlePayloadChange}
validation={validated.validation}
onReset={() => handlePayloadChange(presetPayload(DECISION_PRESETS[0], endpoint, draftModel))}
onReset={handleReset}
/>
)}
</TabsContent>
@ -275,7 +279,8 @@ export default function SystemOneUI({ accessToken, disabledPersonalKeyCreation =
<CurlPreview
baseUrl={getCustomProxyBaseUrl() ?? getProxyBaseUrl()}
endpoint={endpoint}
payload={rawPayload}
payload={validation.payload === undefined ? rawPayload : JSON.stringify(validation.payload)}
authHeaderName={getGlobalLitellmHeaderName()}
/>
</TabsContent>
</Tabs>

View file

@ -0,0 +1,40 @@
import { render, screen } from "@testing-library/react";
import { describe, expect, it } from "vitest";
import { IssueList, ValidationStatus } from "./ValidationFeedback";
import type { PayloadValidation } from "./lib/validatePayload";
const validation = (issues: PayloadValidation<unknown>["issues"]): PayloadValidation<unknown> => ({
isValid: issues.every((issue) => issue.severity !== "error"),
issues,
});
describe("ValidationStatus", () => {
it("counts only errors as issues", () => {
render(
<ValidationStatus
validation={validation([
{ path: "state", message: "Required", severity: "error" },
{ path: "model", message: "Required", severity: "error" },
{ path: "questions.a", message: "Long question", severity: "warning" },
])}
/>,
);
expect(screen.getByText("2 issues")).toBeInTheDocument();
});
it("reports a valid payload when only warnings remain", () => {
render(<ValidationStatus validation={validation([{ path: "q", message: "Long", severity: "warning" }])} />);
expect(screen.getByText("Valid payload")).toBeInTheDocument();
});
});
describe("IssueList", () => {
it("lists every issue with its path and says ready when there are none", () => {
const { rerender } = render(
<IssueList id="issues" validation={validation([{ path: "state", message: "Required", severity: "error" }])} />,
);
expect(screen.getByRole("list", { name: "Payload validation issues" })).toHaveTextContent("stateRequired");
rerender(<IssueList id="issues" validation={validation([])} />);
expect(screen.getByRole("status")).toHaveTextContent("Ready to send");
});
});

View file

@ -7,10 +7,11 @@ describe("buildCurlCommand", () => {
baseUrl: "http://localhost:4000/",
endpoint: "/v1/systemone",
payload: JSON.stringify({ model: "jev-latest", state: "it's broken" }),
authHeaderName: "Authorization",
});
expect(command).toContain("curl -X POST 'http://localhost:4000/v1/systemone'");
expect(command).toContain('-H "Authorization: Bearer $LITELLM_API_KEY"');
expect(command).toContain("-H 'Authorization: Bearer $LITELLM_API_KEY'");
expect(command).not.toContain("sk-");
expect(command).toContain(' "state": "it\'\\\'\'s broken"');
expect(JSON.parse(curlPayload(command) ?? "")).toEqual({ model: "jev-latest", state: "it's broken" });
@ -21,12 +22,29 @@ describe("buildCurlCommand", () => {
baseUrl: "http://proxy.example/$(touch pwned)'; echo x",
endpoint: "/v1/decisions",
payload: "{}",
authHeaderName: "Authorization",
});
expect(command).toContain(`curl -X POST 'http://proxy.example/$(touch pwned)'\\''; echo x/v1/decisions'`);
});
it("sends the key under the proxy's configured auth header name", () => {
const command = buildCurlCommand({
baseUrl: "https://proxy.example",
endpoint: "/v1/systemone",
payload: "{}",
authHeaderName: "X-Litellm-Key",
});
expect(command).toContain("-H 'X-Litellm-Key: Bearer $LITELLM_API_KEY'");
expect(command).not.toContain("Authorization");
});
it("passes a payload that is not JSON through untouched", () => {
const command = buildCurlCommand({ baseUrl: "https://proxy.example", endpoint: "/v1/decisions", payload: "{" });
const command = buildCurlCommand({
baseUrl: "https://proxy.example",
endpoint: "/v1/decisions",
payload: "{",
authHeaderName: "Authorization",
});
expect(command).toContain("'https://proxy.example/v1/decisions'");
expect(curlPayload(command)).toBe("{");
});

View file

@ -2,6 +2,7 @@ export interface CurlCommandInput {
baseUrl: string;
endpoint: "/v1/decisions" | "/v1/systemone";
payload: string;
authHeaderName: string;
}
export const CURL_KEY_PLACEHOLDER = "$LITELLM_API_KEY";
@ -16,10 +17,10 @@ const prettyPayload = (payload: string): string => {
}
};
export const buildCurlCommand = ({ baseUrl, endpoint, payload }: CurlCommandInput): string =>
export const buildCurlCommand = ({ baseUrl, endpoint, payload, authHeaderName }: CurlCommandInput): string =>
[
`curl -X POST ${shellSingleQuote(`${baseUrl.replace(/\/+$/, "")}${endpoint}`)}`,
` -H "Authorization: Bearer ${CURL_KEY_PLACEHOLDER}"`,
` -H ${shellSingleQuote(`${authHeaderName}: Bearer ${CURL_KEY_PLACEHOLDER}`)}`,
` -H "Content-Type: application/json"`,
` -d ${shellSingleQuote(prettyPayload(payload))}`,
].join(" \\\n");