Runs / transfer-form Batch Runs from different design-system versions should not be compared.
The page A screenshot in each theme, as the benchmark took it.
page.tsx As the agent left it; marked lines broke a rule.
Violations 5 counted, under 2 rules. “Not counted” marks a compiler error that restates a design-system violation, “Ignored” one the agent silenced with a comment.
Steps One row per model call, with the tools it asked for. An agent that reads the guidelines before writing shows it here; what a checker or submit_view answered is under its call.
Step Tools Tokens in Tokens out Cost 0 get_guidelines, list_files 364 48 $0.0002 1 read_file, list_components 1,441 68 $0.0005 2 get_component, get_component, get_component, get_component 866 128 $0.0004
e02ef3974528
Output cap The provider's default 4 import {
5 Badge,
6 Button,
7 Card,
8 CardBody,
9 CardDescription,
10 CardFooter,
11 CardHeader,
12 CardTitle,
13 FormField,
14 Input,
15 Select,
16 } from "@vektos/ds";
17 import { css } from "styled-system/css";
18 import data from "./fixture.json";
19
20 const money = new Intl.NumberFormat("en-IE", {
21 style: "currency",
22 currency: data.currency,
23 });
24
25 const accounts = data.accounts;
26
27 type Confirmation = {
28 amount: number;
29 beneficiaryName: string;
30 beneficiaryIban: string;
31 accountName: string;
32 reference: string;
33 };
34
35 /**
36 * Reads a human-typed amount. Accepts "1250", "1250.40", "1.250,40" and
37 * "1 250,40"; returns null when the text is not a number at all.
38 */
39 function parseAmount(raw: string): number | null {
40 const compact = raw.trim().replace(/\s/g, "");
41 if (!compact) return null;
42
43 const lastComma = compact.lastIndexOf(",");
44 const lastDot = compact.lastIndexOf(".");
45 let normalized = compact;
46
47 if (lastComma > -1 && lastDot > -1) {
48 const decimal = lastComma > lastDot ? "," : ".";
49 const thousands = decimal === "," ? "." : ",";
50 normalized = compact.split(thousands).join("").replace(decimal, ".");
51 } else if (lastComma > -1) {
52 normalized = compact.split(",").join(".");
53 }
54
55 if (!/^\d+(\.\d+)?$/.test(normalized)) return null;
56
57 const value = Number(normalized);
58 return Number.isFinite(value) ? value : null;
59 }
60
61 function normalizeIban(raw: string): string {
62 return raw.replace(/\s/g, "").toUpperCase();
63 }
64
65 export default function Page() {
66 const [accountId, setAccountId] = useState<string>(data.defaultAccountId);
67 const [beneficiaryName, setBeneficiaryName] = useState("");
68 const [beneficiaryIban, setBeneficiaryIban] = useState("");
69 const [amount, setAmount] = useState("");
70 const [reference, setReference] = useState("");
71 const [showFieldErrors, setShowFieldErrors] = useState(false);
72 const [confirmation, setConfirmation] = useState<Confirmation | null>(null);
73
74 const selectedAccount =
75 accounts.find((account) => account.id === accountId) ?? accounts[0];
76 const available = selectedAccount.available;
77
78 const parsedAmount = parseAmount(amount);
79 const normalizedIban = normalizeIban(beneficiaryIban);
80
81 // Amount: the balance check is reported as soon as it is true; the other
82 // amount problems wait until the user has tried to submit.
83 const overBalanceError =
84 parsedAmount !== null && parsedAmount > 0 && parsedAmount > available
85 ? `The amount is higher than the ${money.format(available)} available on this account.`
86 : null;
87 const amountProblem = amount.trim()
88 ? parsedAmount === null
89 ? "Enter a number, for example 125,40."
90 : parsedAmount <= 0
91 ? "Enter an amount greater than zero."
92 : null
93 : "Enter the amount to send.";
94 const amountError = overBalanceError ?? (showFieldErrors ? amountProblem : null);
95
96 const nameProblem = beneficiaryName.trim()
97 ? null
98 : "Enter the name of the beneficiary.";
99 const ibanProblem = normalizedIban
100 ? /^[A-Z]{2}\d{2}[A-Z0-9]{10,30}$/.test(normalizedIban)
101 ? null
102 : "Enter a valid IBAN, such as IT60 X054 2811 1010 0000 0123 456."
103 : "Enter the IBAN of the beneficiary.";
104
105 const canSubmit =
106 !overBalanceError && !amountProblem && !nameProblem && !ibanProblem;
107
108 function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
109 event.preventDefault();
110 setShowFieldErrors(true);
111
112 if (!canSubmit || parsedAmount === null) return;
113
114 setConfirmation({
115 amount: parsedAmount,
116 beneficiaryName: beneficiaryName.trim(),
117 beneficiaryIban: beneficiaryIban.trim(),
118 accountName: selectedAccount.name,
119 reference: reference.trim(),
120 });
121 }
122
123 function handleReset() {
124 setConfirmation(null);
125 setBeneficiaryName("");
126 setBeneficiaryIban("");
127 setAmount("");
128 setReference("");
129 setShowFieldErrors(false);
130 }
131
132 return (
133 <div
134 className={
135 "vektos " +
136 css({
137 bg: "bg.canvas",
138 minHeight: "full",
139 px: "4",
140 py: "8",
141 })
142 }
143 >
144 <main
145 className={css({
146 maxWidth: "lg",
147 mx: "auto",
148 display: "flex",
149 flexDirection: "column",
150 gap: "6",
151 })}
152 >
153 <header
154 className={css({ display: "flex", flexDirection: "column", gap: "1" })}
155 >
156 <h1
157 className={css({
158 margin: "0",
159 fontSize: "lg",
160 fontWeight: "semibold",
161 color: "fg.default",
162 })}
163 >
164 Send a SEPA transfer
165 </h1>
166 <p
167 className={css({ margin: "0", fontSize: "sm", color: "fg.muted" })}
168 >
169 Pick the account to pay from, then enter the beneficiary and the
170 amount.
171 </p>
172 </header>
173
174 {confirmation ? (
175 <div role="status" aria-live="polite">
176 <Card>
177 <CardHeader>
178 <div
179 className={css({
180 display: "flex",
181 alignItems: "center",
182 gap: "2",
183 })}
184 >
185 <CardTitle>Transfer sent</CardTitle>
186 <Badge tone="success">Sent</Badge>
187 </div>
188 <CardDescription>
189 {money.format(confirmation.amount)} to{" "}
190 {confirmation.beneficiaryName}. It usually arrives within one
191 business day.
192 </CardDescription>
193 </CardHeader>
194 <CardBody>
195 <dl
196 className={css({
197 display: "flex",
198 flexDirection: "column",
199 gap: "2",
200 fontSize: "sm",
201 margin: "0",
202 })}
203 >
204 <div
205 className={css({
206 display: "flex",
207 justifyContent: "space-between",
208 gap: "4",
209 })}
210 >
211 <dt className={css({ color: "fg.muted" })}>Amount</dt>
212 <dd
213 className={css({
214 margin: "0",
215 fontWeight: "semibold",
216 color: "fg.default",
217 })}
218 >
219 {money.format(confirmation.amount)}
220 </dd>
221 </div>
222 <div
223 className={css({
224 display: "flex",
225 justifyContent: "space-between",
226 gap: "4",
227 })}
228 >
229 <dt className={css({ color: "fg.muted" })}>Beneficiary</dt>
230 <dd
231 className={css({ margin: "0", color: "fg.default" })}
232 >
233 {confirmation.beneficiaryName}
234 </dd>
235 </div>
236 <div
237 className={css({
238 display: "flex",
239 justifyContent: "space-between",
240 gap: "4",
241 })}
242 >
243 <dt className={css({ color: "fg.muted" })}>IBAN</dt>
244 <dd
245 className={css({ margin: "0", color: "fg.default" })}
246 >
247 {confirmation.beneficiaryIban}
248 </dd>
249 </div>
250 <div
251 className={css({
252 display: "flex",
253 justifyContent: "space-between",
254 gap: "4",
255 })}
256 >
257 <dt className={css({ color: "fg.muted" })}>From</dt>
258 <dd
259 className={css({ margin: "0", color: "fg.default" })}
260 >
261 {confirmation.accountName}
262 </dd>
263 </div>
264 {confirmation.reference ? (
265 <div
266 className={css({
267 display: "flex",
268 justifyContent: "space-between",
269 gap: "4",
270 })}
271 >
272 <dt className={css({ color: "fg.muted" })}>Reference</dt>
273 <dd
274 className={css({ margin: "0", color: "fg.default" })}
275 >
276 {confirmation.reference}
277 </dd>
278 </div>
279 ) : null}
280 </dl>
281 </CardBody>
282 <CardFooter>
283 <Button variant="outline" size="sm" onClick={handleReset}>
284 Make another transfer
285 </Button>
286 </CardFooter>
287 </Card>
288 </div>
289 ) : (
290 <form onSubmit={handleSubmit} noValidate>
291 <Card>
292 <CardHeader>
293 <CardTitle>Transfer details</CardTitle>
294 <CardDescription>
295 All amounts are in {data.currency}.
296 </CardDescription>
297 </CardHeader>
298 <CardBody>
299 <div
300 className={css({
301 display: "flex",
302 flexDirection: "column",
303 gap: "4",
304 })}
305 >
306 <FormField
307 label="From account"
308 helperText={selectedAccount.iban}
309 >
310 <Select
311 options={accounts.map((account) => ({
312 label: `${account.name} · ${money.format(account.available)}`,
313 value: account.id,
314 }))}
315 value={selectedAccount.id}
316 onValueChange={setAccountId}
317 placeholder="Choose an account"
318 />
319 </FormField>
320
321 <div
322 className={css({
323 display: "flex",
324 alignItems: "baseline",
325 justifyContent: "space-between",
326 gap: "3",
327 bg: "bg.subtle",
328 px: "3",
329 py: "2",
330 rounded: "md",
331 })}
332 >
333 <span className={css({ fontSize: "sm", color: "fg.muted" })}>
334 Available balance
335 </span>
336 <span
337 className={css({
338 fontSize: "md",
339 fontWeight: "semibold",
340 color: "fg.default",
341 })}
342 >
343 {money.format(available)}
344 </span>
345 </div>
346
347 <FormField
348 label="Beneficiary name"
349 error={showFieldErrors ? nameProblem : undefined}
350 >
351 <Input
352 value={beneficiaryName}
353 onChange={(event) => setBeneficiaryName(event.target.value)}
354 placeholder="Maria Rossi"
355 autoComplete="off"
356 />
357 </FormField>
358
359 <FormField
360 label="Beneficiary IBAN"
361 error={showFieldErrors ? ibanProblem : undefined}
362 >
363 <Input
364 value={beneficiaryIban}
365 onChange={(event) =>
366 setBeneficiaryIban(event.target.value)
367 }
368 placeholder="IT60 X054 2811 1010 0000 0123 456"
369 autoComplete="off"
370 autoCapitalize="characters"
371 spellCheck={false}
372 />
373 </FormField>
374
375 <FormField
376 label={`Amount (${data.currency})`}
377 helperText={`Up to ${money.format(available)} from this account.`}
378 error={amountError ?? undefined}
379 >
380 <Input
381 inputMode="decimal"
382 value={amount}
383 onChange={(event) => setAmount(event.target.value)}
384 placeholder="0,00"
385 autoComplete="off"
386 />
387 </FormField>
388
389 <FormField
390 label="Reference"
391 helperText="Optional. Shown on the statement of both accounts."
392 >
393 <Input
394 value={reference}
395 onChange={(event) => setReference(event.target.value)}
396 placeholder="Invoice 2026-114"
397 autoComplete="off"
398 />
399 </FormField>
400 </div>
401 </CardBody>
402 <CardFooter>
403 <Button type="submit">Send transfer</Button>
404 </CardFooter>
405 </Card>
406 </form>
407 )}
408 </main>
409 </div>
410 );
411 }
412
get_component, list_tokens
4 list_tokens, list_tokens, list_tokens, list_tokens 1,736 132 $0.0007
5 get_component, list_tokens 755 3,964 $0.0050
6 write_file 4,710 6,564 $0.0093