Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/web-evals/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"dependencies": {
"@hookform/resolvers": "^5.1.1",
"@radix-ui/react-alert-dialog": "^1.1.7",
"@radix-ui/react-checkbox": "^1.1.5",
"@radix-ui/react-dialog": "^1.1.6",
"@radix-ui/react-dropdown-menu": "^2.1.7",
"@radix-ui/react-label": "^2.1.2",
Expand Down
3 changes: 1 addition & 2 deletions apps/web-evals/src/actions/runs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ import { CreateRun } from "@/lib/schemas"

const EVALS_REPO_PATH = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../../../../evals")

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function createRun({ suite, exercises = [], systemPrompt, timeout, ...values }: CreateRun) {
export async function createRun({ suite, exercises = [], timeout, ...values }: CreateRun) {
const run = await _createRun({
...values,
timeout,
Expand Down
24 changes: 0 additions & 24 deletions apps/web-evals/src/app/api/health/route.ts

This file was deleted.

207 changes: 119 additions & 88 deletions apps/web-evals/src/app/runs/new/new-run.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
"use client"

import { useCallback, useRef, useState } from "react"
import { useCallback, useState } from "react"
import { useRouter } from "next/navigation"
import { z } from "zod"
import { useQuery } from "@tanstack/react-query"
import { useForm, FormProvider } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import fuzzysort from "fuzzysort"
import { toast } from "sonner"
import { X, Rocket, Check, ChevronsUpDown, SlidersHorizontal, CircleCheck } from "lucide-react"
import { X, Rocket, Check, ChevronsUpDown, SlidersHorizontal } from "lucide-react"

import { globalSettingsSchema, providerSettingsSchema, EVALS_SETTINGS, getModelId } from "@roo-code/types"

import { createRun } from "@/actions/runs"
import { getExercises } from "@/actions/exercises"

import {
createRunSchema,
type CreateRun,
MODEL_DEFAULT,
createRunSchema,
CONCURRENCY_MIN,
CONCURRENCY_MAX,
CONCURRENCY_DEFAULT,
Expand All @@ -26,14 +25,19 @@ import {
TIMEOUT_DEFAULT,
} from "@/lib/schemas"
import { cn } from "@/lib/utils"

import { useOpenRouterModels } from "@/hooks/use-open-router-models"
import { useRooCodeCloudModels } from "@/hooks/use-roo-code-cloud-models"

import {
Button,
Checkbox,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
Input,
Textarea,
Tabs,
TabsList,
Expand All @@ -48,36 +52,40 @@ import {
Popover,
PopoverContent,
PopoverTrigger,
ScrollArea,
ScrollBar,
Slider,
Label,
FormDescription,
} from "@/components/ui"

import { SettingsDiff } from "./settings-diff"

export function NewRun() {
const router = useRouter()

const [mode, setMode] = useState<"openrouter" | "settings">("openrouter")
const [modelSearchValue, setModelSearchValue] = useState("")
const [provider, setModelSource] = useState<"roo" | "openrouter" | "other">("roo")
const [modelPopoverOpen, setModelPopoverOpen] = useState(false)
const [useNativeToolProtocol, setUseNativeToolProtocol] = useState(true)

const modelSearchResultsRef = useRef<Map<string, number>>(new Map())
const modelSearchValueRef = useRef("")
const openRouter = useOpenRouterModels()
const rooCodeCloud = useRooCodeCloudModels()
const models = provider === "openrouter" ? openRouter.data : rooCodeCloud.data
const searchValue = provider === "openrouter" ? openRouter.searchValue : rooCodeCloud.searchValue
const setSearchValue = provider === "openrouter" ? openRouter.setSearchValue : rooCodeCloud.setSearchValue
const onFilter = provider === "openrouter" ? openRouter.onFilter : rooCodeCloud.onFilter

const models = useOpenRouterModels()
const exercises = useQuery({ queryKey: ["getExercises"], queryFn: () => getExercises() })

const form = useForm<CreateRun>({
resolver: zodResolver(createRunSchema),
defaultValues: {
model: MODEL_DEFAULT,
model: "",
description: "",
suite: "full",
exercises: [],
settings: undefined,
concurrency: CONCURRENCY_DEFAULT,
timeout: TIMEOUT_DEFAULT,
jobToken: "",
},
})

Expand All @@ -93,8 +101,20 @@ export function NewRun() {
const onSubmit = useCallback(
async (values: CreateRun) => {
try {
if (mode === "openrouter") {
values.settings = { ...(values.settings || {}), openRouterModelId: model }
if (provider === "openrouter") {
values.settings = {
...(values.settings || {}),
apiProvider: "openrouter",
openRouterModelId: model,
toolProtocol: useNativeToolProtocol ? "native" : "xml",
}
} else if (provider === "roo") {
values.settings = {
...(values.settings || {}),
apiProvider: "roo",
apiModelId: model,
toolProtocol: useNativeToolProtocol ? "native" : "xml",
}
}

const { id } = await createRun(values)
Expand All @@ -103,36 +123,15 @@ export function NewRun() {
toast.error(e instanceof Error ? e.message : "An unknown error occurred.")
}
},
[mode, model, router],
)

const onFilterModels = useCallback(
(value: string, search: string) => {
if (modelSearchValueRef.current !== search) {
modelSearchValueRef.current = search
modelSearchResultsRef.current.clear()

for (const {
obj: { id },
score,
} of fuzzysort.go(search, models.data || [], {
key: "name",
})) {
modelSearchResultsRef.current.set(id, score)
}
}

return modelSearchResultsRef.current.get(value) ?? 0
},
[models.data],
[provider, model, router, useNativeToolProtocol],
)

const onSelectModel = useCallback(
(model: string) => {
setValue("model", model)
setModelPopoverOpen(false)
},
[setValue],
[setValue, setModelPopoverOpen],
)

const onImportSettings = useCallback(
Expand Down Expand Up @@ -160,7 +159,6 @@ export function NewRun() {

setValue("model", getModelId(providerSettings) ?? "")
setValue("settings", { ...EVALS_SETTINGS, ...providerSettings, ...globalSettings })
setMode("settings")

event.target.value = ""
} catch (e) {
Expand All @@ -177,13 +175,44 @@ export function NewRun() {
<form
onSubmit={form.handleSubmit(onSubmit)}
className="flex flex-col justify-center divide-y divide-primary *:py-5">
<div className="flex flex-row justify-between gap-4">
{mode === "openrouter" && (
<FormField
control={form.control}
name="model"
render={() => (
<FormItem className="flex-1">
<FormField
control={form.control}
name="model"
render={() => (
<FormItem>
<Tabs
value={provider}
onValueChange={(value) => setModelSource(value as "roo" | "openrouter" | "other")}>
<TabsList className="mb-2">
<TabsTrigger value="roo">Roo Code Cloud</TabsTrigger>
<TabsTrigger value="openrouter">OpenRouter</TabsTrigger>
<TabsTrigger value="other">Other</TabsTrigger>
</TabsList>
</Tabs>

{provider === "other" ? (
<div className="space-y-2 overflow-auto">
<Button
type="button"
variant="secondary"
onClick={() => document.getElementById("json-upload")?.click()}
className="w-full">
<SlidersHorizontal />
Import Settings
</Button>
<input
id="json-upload"
type="file"
accept="application/json"
className="hidden"
onChange={onImportSettings}
/>
{settings && (
<SettingsDiff defaultSettings={EVALS_SETTINGS} customSettings={settings} />
)}
</div>
) : (
<>
<Popover open={modelPopoverOpen} onOpenChange={setModelPopoverOpen}>
<PopoverTrigger asChild>
<Button
Expand All @@ -192,25 +221,23 @@ export function NewRun() {
aria-expanded={modelPopoverOpen}
className="flex items-center justify-between">
<div>
{models.data?.find(({ id }) => id === model)?.name ||
model ||
"Select OpenRouter Model"}
{models?.find(({ id }) => id === model)?.name || `Select`}
</div>
<ChevronsUpDown className="opacity-50" />
</Button>
</PopoverTrigger>
<PopoverContent className="p-0 w-[var(--radix-popover-trigger-width)]">
<Command filter={onFilterModels}>
<Command filter={onFilter}>
<CommandInput
placeholder="Search"
value={modelSearchValue}
onValueChange={setModelSearchValue}
value={searchValue}
onValueChange={setSearchValue}
className="h-9"
/>
<CommandList>
<CommandEmpty>No model found.</CommandEmpty>
<CommandGroup>
{models.data?.map(({ id, name }) => (
{models?.map(({ id, name }) => (
<CommandItem
key={id}
value={id}
Expand All @@ -229,45 +256,49 @@ export function NewRun() {
</Command>
</PopoverContent>
</Popover>
<FormMessage />
</FormItem>
)}
/>
)}

<FormItem className="flex-1">
<Button
type="button"
variant="secondary"
onClick={() => document.getElementById("json-upload")?.click()}>
<SlidersHorizontal />
Import Settings
</Button>
<input
id="json-upload"
type="file"
accept="application/json"
className="hidden"
onChange={onImportSettings}
/>
{settings && (
<ScrollArea className="max-h-64 border rounded-sm">
<>
<div className="flex items-center gap-1 p-2 border-b">
<CircleCheck className="size-4 text-ring" />
<div className="text-sm">
Imported valid Roo Code settings. Showing differences from default
settings.
</div>
<div className="flex items-center gap-1.5">
<Checkbox
id="native"
checked={useNativeToolProtocol}
onCheckedChange={(checked) =>
setUseNativeToolProtocol(checked === true)
}
/>
<Label htmlFor="native">Use Native Tool Calls</Label>
</div>
<SettingsDiff defaultSettings={EVALS_SETTINGS} customSettings={settings} />
</>
<ScrollBar orientation="horizontal" />
</ScrollArea>
)}

<FormMessage />
</FormItem>
)}
/>

{provider === "roo" && (
<FormField
control={form.control}
name="jobToken"
render={({ field }) => (
<FormItem>
<FormLabel>Roo Code Cloud Token</FormLabel>
<FormControl>
<Input type="password" {...field} />
</FormControl>
<FormMessage />
<FormDescription>
If you have access to the Roo Code Cloud repository then you can generate a
token with:
<br />
<code className="text-xs">
pnpm --filter @roo-code-cloud/auth production:create-job-token [org]
[timeout]
</code>
</FormDescription>
</FormItem>
)}
<FormMessage />
</FormItem>
</div>
/>
)}

<FormField
control={form.control}
Expand Down
Loading
Loading