|
1 | 1 | "use client" |
2 | 2 |
|
3 | | -import { useMemo } from "react" |
| 3 | +import { useMemo, useState } from "react" // Added useState |
4 | 4 | import { useRouter } from "next/navigation" |
5 | | -import { LoaderCircle, Download, ArrowLeft } from "lucide-react" |
| 5 | +import { LoaderCircle, Download, ArrowLeft, ChevronDown, ChevronUp } from "lucide-react" // Added Chevrons |
6 | 6 |
|
7 | 7 | import * as db from "@evals/db" |
8 | | - |
| 8 | +import { rooCodeDefaults } from "@evals/types" // Added rooCodeDefaults |
| 9 | +import { CONCURRENCY_DEFAULT } from "@/lib/schemas" // Added CONCURRENCY_DEFAULT |
9 | 10 | import { formatCurrency, formatDuration, formatTokens } from "@/lib/formatters" |
10 | 11 | import { useRunStatus } from "@/hooks/use-run-status" |
11 | | -import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, Button } from "@/components/ui" |
| 12 | +import { |
| 13 | + Table, |
| 14 | + TableBody, |
| 15 | + TableCell, |
| 16 | + TableHead, |
| 17 | + TableHeader, |
| 18 | + TableRow, |
| 19 | + Button, |
| 20 | + Collapsible, // Added Collapsible components |
| 21 | + CollapsibleContent, |
| 22 | + CollapsibleTrigger, |
| 23 | + // ScrollArea, // Removed ScrollArea |
| 24 | +} from "@/components/ui" |
| 25 | +// import { SettingsDiff } from "../new/settings-diff" // Removed SettingsDiff |
12 | 26 |
|
13 | 27 | import { TaskStatus } from "./task-status" |
14 | 28 | import { ConnectionStatus } from "./connection-status" |
15 | 29 | import { EventSourceStatus } from "@/hooks/use-event-source" |
| 30 | +import { RooCodeSettings } from "@evals/types" // Added RooCodeSettings type |
16 | 31 |
|
17 | 32 | type TaskMetrics = Pick<db.TaskMetrics, "tokensIn" | "tokensOut" | "tokensContext" | "duration" | "cost"> |
18 | 33 |
|
19 | 34 | interface Task extends db.Task { |
20 | 35 | taskMetrics?: TaskMetrics | null |
21 | 36 | } |
22 | 37 |
|
| 38 | +// Mapping from setting keys to human-readable labels |
| 39 | +const settingLabels: Partial<Record<keyof RooCodeSettings, string>> = { |
| 40 | + modelTemperature: "Model Temperature", |
| 41 | + reasoningEffort: "Reasoning Effort", |
| 42 | + includeMaxTokens: "Include Max Tokens", |
| 43 | + terminalOutputLineLimit: "Terminal Output Limit", |
| 44 | + terminalShellIntegrationTimeout: "Terminal Integration Timeout", |
| 45 | + // terminalShellIntegrationDisabled: "Terminal Integration Disabled", // Removed incorrect key |
| 46 | + terminalCommandDelay: "Terminal Command Delay", |
| 47 | + terminalPowershellCounter: "Terminal PowerShell Counter", |
| 48 | + terminalZshClearEolMark: "Terminal Zsh Clear EOL Mark", |
| 49 | + terminalZshOhMy: "Terminal Zsh Oh My", |
| 50 | + terminalZshP10k: "Terminal Zsh P10k", |
| 51 | + terminalZdotdir: "Terminal Zdotdir", |
| 52 | + // terminalCompressProgressBar: "Compress Terminal Progress", // Removed incorrect key |
| 53 | + allowedCommands: "Allowed Commands", |
| 54 | + maxReadFileLine: "Max Read File Line", |
| 55 | + maxOpenTabsContext: "Max Open Tabs Context", |
| 56 | + maxWorkspaceFiles: "Max Workspace Files", |
| 57 | + rateLimitSeconds: "Rate Limit (s)", |
| 58 | + requestDelaySeconds: "Request Delay (s)", |
| 59 | + writeDelayMs: "Write Delay (ms)", |
| 60 | + fuzzyMatchThreshold: "Fuzzy Match Threshold", |
| 61 | + autoApprovalEnabled: "Auto-Approval", |
| 62 | + alwaysAllowReadOnly: "Always Allow ReadOnly (Workspace)", |
| 63 | + alwaysAllowReadOnlyOutsideWorkspace: "Always Allow ReadOnly (Outside)", |
| 64 | + alwaysAllowWrite: "Always Allow Write (Workspace)", |
| 65 | + alwaysAllowWriteOutsideWorkspace: "Always Allow Write (Outside)", |
| 66 | + alwaysAllowBrowser: "Always Allow Browser", |
| 67 | + alwaysApproveResubmit: "Always Approve Resubmit", |
| 68 | + alwaysAllowMcp: "Always Allow MCP", |
| 69 | + alwaysAllowModeSwitch: "Always Allow Mode Switch", |
| 70 | + alwaysAllowSubtasks: "Always Allow Subtasks", |
| 71 | + alwaysAllowExecute: "Always Allow Execute", |
| 72 | + diffEnabled: "Diff View Enabled", |
| 73 | + // Add more labels as needed |
| 74 | +} |
| 75 | + |
| 76 | +// Function to format setting values for display |
| 77 | +const formatSettingValue = (value: any): string => { |
| 78 | + if (typeof value === "boolean") { |
| 79 | + return value ? "Enabled" : "Disabled" |
| 80 | + } |
| 81 | + if (Array.isArray(value)) { |
| 82 | + // Handle '*' specifically for allowedCommands |
| 83 | + if (value.length === 1 && value[0] === "*") { |
| 84 | + return "All (*)" |
| 85 | + } |
| 86 | + return value.join(", ") || "(empty)" |
| 87 | + } |
| 88 | + if (value === null || value === undefined) { |
| 89 | + return "(default)" |
| 90 | + } |
| 91 | + return String(value) |
| 92 | +} |
| 93 | + |
23 | 94 | export function Run({ run }: { run: db.Run }) { |
24 | 95 | const router = useRouter() |
| 96 | + const [isSettingsOpen, setIsSettingsOpen] = useState(false) // State for settings collapsible |
25 | 97 | const { tasks, status, tokenUsage, usageUpdatedAt } = useRunStatus(run) as { |
26 | 98 | tasks: Task[] |
27 | 99 | status: EventSourceStatus |
@@ -95,38 +167,126 @@ export function Run({ run }: { run: db.Run }) { |
95 | 167 | document.body.removeChild(link) |
96 | 168 | } |
97 | 169 |
|
| 170 | + // Filter and format settings that differ from defaults |
| 171 | + const nonDefaultSettings = useMemo(() => { |
| 172 | + const settings = (run.settings || {}) as Partial<RooCodeSettings> // Cast to partial for easier comparison |
| 173 | + const defaults = rooCodeDefaults as RooCodeSettings |
| 174 | + const diff: { label: string; value: string }[] = [] |
| 175 | + |
| 176 | + // Iterate over known setting keys with labels |
| 177 | + for (const key in settingLabels) { |
| 178 | + const typedKey = key as keyof RooCodeSettings |
| 179 | + const runValue = settings[typedKey] |
| 180 | + const defaultValue = defaults[typedKey] |
| 181 | + |
| 182 | + // Check if the key exists in run settings and differs from default |
| 183 | + if ( |
| 184 | + runValue !== undefined && |
| 185 | + runValue !== null && // Explicitly check for null |
| 186 | + JSON.stringify(runValue) !== JSON.stringify(defaultValue) // Compare values robustly |
| 187 | + ) { |
| 188 | + diff.push({ |
| 189 | + label: settingLabels[typedKey]!, |
| 190 | + value: formatSettingValue(runValue), |
| 191 | + }) |
| 192 | + } |
| 193 | + } |
| 194 | + // Add concurrency separately if it differs from the imported default |
| 195 | + if (run.concurrency !== CONCURRENCY_DEFAULT) { |
| 196 | + diff.push({ |
| 197 | + label: "Concurrency", |
| 198 | + value: formatSettingValue(run.concurrency), |
| 199 | + }) |
| 200 | + } |
| 201 | + |
| 202 | + // Sort alphabetically by label |
| 203 | + diff.sort((a, b) => a.label.localeCompare(b.label)) |
| 204 | + |
| 205 | + return diff |
| 206 | + }, [run.settings, run.concurrency]) |
| 207 | + |
| 208 | + const hasNonDefaultSettings = nonDefaultSettings.length > 0 |
| 209 | + |
98 | 210 | return ( |
99 | 211 | <> |
100 | 212 | <div> |
101 | 213 | <div className="mb-6"> |
102 | | - <div className="flex justify-between items-center"> |
| 214 | + <div className="flex justify-between items-start"> |
| 215 | + {" "} |
| 216 | + {/* Changed items-center to items-start */} |
103 | 217 | <div> |
104 | 218 | <h1 className="text-3xl font-bold">Run #{run.id}</h1> |
105 | | - <div className="grid grid-cols-2 gap-x-8 gap-y-2 mt-4"> |
| 219 | + <div className="grid grid-cols-2 md:grid-cols-4 gap-x-8 gap-y-2 mt-4"> |
| 220 | + {" "} |
| 221 | + {/* Use 4 columns */} |
| 222 | + {/* API Provider */} |
106 | 223 | <div> |
107 | | - <div className="text-sm font-medium text-muted-foreground">Provider</div> |
108 | | - <div>{run.model.split("/")[0] || "Unknown"}</div> |
| 224 | + <div className="text-sm font-medium text-muted-foreground">API Provider</div> |
| 225 | + <div>{run.settings?.apiProvider || "Unknown"}</div> |
109 | 226 | </div> |
| 227 | + {/* Model */} |
110 | 228 | <div> |
111 | 229 | <div className="text-sm font-medium text-muted-foreground">Model</div> |
112 | 230 | <div>{run.model.includes("/") ? run.model.split("/")[1] : run.model}</div> |
113 | 231 | </div> |
| 232 | + {/* Temperature */} |
114 | 233 | <div> |
115 | 234 | <div className="text-sm font-medium text-muted-foreground">Temperature</div> |
116 | 235 | <div> |
117 | 236 | {run.settings?.modelTemperature !== undefined && |
118 | | - run.settings?.modelTemperature !== null |
| 237 | + run.settings?.modelTemperature !== null && |
| 238 | + run.settings?.modelTemperature !== rooCodeDefaults.modelTemperature |
119 | 239 | ? run.settings.modelTemperature |
120 | | - : "Default"} |
| 240 | + : "(default)"} |
121 | 241 | </div> |
122 | 242 | </div> |
| 243 | + {/* Concurrency */} |
| 244 | + <div> |
| 245 | + <div className="text-sm font-medium text-muted-foreground">Concurrency</div> |
| 246 | + <div>{run.concurrency !== CONCURRENCY_DEFAULT ? run.concurrency : "(default)"}</div> |
| 247 | + </div> |
| 248 | + {/* Notes */} |
123 | 249 | {run.description && ( |
124 | | - <div className="col-span-2"> |
| 250 | + <div className="col-span-full md:col-span-4"> |
| 251 | + {" "} |
| 252 | + {/* Span full width */} |
125 | 253 | <div className="text-sm font-medium text-muted-foreground">Notes</div> |
126 | 254 | <div className="max-w-[500px]">{run.description}</div> |
127 | 255 | </div> |
128 | 256 | )} |
129 | 257 | </div> |
| 258 | + {/* Settings Collapsible Section */} |
| 259 | + {hasNonDefaultSettings && ( // Only show if there are non-default settings |
| 260 | + <Collapsible |
| 261 | + open={isSettingsOpen} |
| 262 | + onOpenChange={setIsSettingsOpen} |
| 263 | + className="mt-4 border rounded-md max-w-xl"> |
| 264 | + {" "} |
| 265 | + {/* Added max-width */} |
| 266 | + <CollapsibleTrigger asChild> |
| 267 | + <Button variant="ghost" className="flex w-full justify-between p-2"> |
| 268 | + <span className="font-medium"> |
| 269 | + Other Configuration ({nonDefaultSettings.length} non-default) |
| 270 | + </span> |
| 271 | + {isSettingsOpen ? ( |
| 272 | + <ChevronUp className="h-4 w-4" /> |
| 273 | + ) : ( |
| 274 | + <ChevronDown className="h-4 w-4" /> |
| 275 | + )} |
| 276 | + </Button> |
| 277 | + </CollapsibleTrigger> |
| 278 | + <CollapsibleContent className="p-4"> |
| 279 | + <div className="space-y-2"> |
| 280 | + {nonDefaultSettings.map(({ label, value }) => ( |
| 281 | + <div key={label} className="flex justify-between text-sm"> |
| 282 | + <span className="text-muted-foreground">{label}:</span> |
| 283 | + <span className="font-mono text-right">{value}</span> |
| 284 | + </div> |
| 285 | + ))} |
| 286 | + </div> |
| 287 | + </CollapsibleContent> |
| 288 | + </Collapsible> |
| 289 | + )} |
130 | 290 | </div> |
131 | 291 | <div className="flex items-center gap-4"> |
132 | 292 | <Button variant="outline" size="sm" onClick={() => router.push("/")} title="Back to runs"> |
|
0 commit comments