Runs / payment-approval 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 3 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 1,260 47 $0.0004 1 read_file, list_components 2,592 54 $0.0008 2 get_component, get_component, get_component, get_component 932 128 $0.0005
e02ef3974528
Output cap The provider's default 4 import {
5 Badge,
6 Button,
7 Card,
8 CardDescription,
9 CardHeader,
10 CardTitle,
11 Dialog,
12 DialogClose,
13 DialogContent,
14 DialogFooter,
15 DialogTrigger,
16 Table,
17 TableBody,
18 TableCell,
19 TableHead,
20 TableHeader,
21 TableRow,
22 } from "@vektos/ds";
23 import { css } from "styled-system/css";
24 import data from "./fixture.json";
25
26 type Scheme = keyof typeof data.fees;
27
28 const schemeLabels: Record<Scheme, string> = {
29 sepa: "SEPA credit transfer",
30 instant: "SEPA Instant",
31 };
32
33 const monthNames = [
34 "Jan",
35 "Feb",
36 "Mar",
37 "Apr",
38 "May",
39 "Jun",
40 "Jul",
41 "Aug",
42 "Sep",
43 "Oct",
44 "Nov",
45 "Dec",
46 ];
47
48 const amountFormatter = new Intl.NumberFormat("en-GB", {
49 minimumFractionDigits: 2,
50 maximumFractionDigits: 2,
51 });
52
53 const moneyFormatter = new Intl.NumberFormat("en-GB", {
54 style: "currency",
55 currency: data.currency,
56 currencyDisplay: "code",
57 });
58
59 function formatAmount(value: number): string {
60 return amountFormatter.format(value);
61 }
62
63 function formatMoney(value: number): string {
64 return moneyFormatter.format(value);
65 }
66
67 function formatDueDate(isoDate: string): string {
68 const [year, month, day] = isoDate.split("-");
69 return `${day} ${monthNames[Number(month) - 1]} ${year}`;
70 }
71
72 function feeFor(scheme: string): number {
73 return data.fees[scheme as Scheme] ?? 0;
74 }
75
76 function schemeLabel(scheme: string): string {
77 return schemeLabels[scheme as Scheme] ?? scheme;
78 }
79
80 interface SummaryRowProps {
81 label: string;
82 value: string;
83 /** Emphasises the value, for the total line. */
84 strong?: boolean;
85 /** Draws a divider above the row, separating it from the details. */
86 divider?: boolean;
87 }
88
89 function SummaryRow({ label, value, strong = false, divider = false }: SummaryRowProps) {
90 const rowClass = divider
91 ? css({
92 display: "flex",
93 alignItems: "baseline",
94 justifyContent: "space-between",
95 gap: "6",
96 borderTopWidth: "thin",
97 borderTopStyle: "solid",
98 borderColor: "border.default",
99 paddingBlockStart: "3",
100 })
101 : css({
102 display: "flex",
103 alignItems: "baseline",
104 justifyContent: "space-between",
105 gap: "6",
106 });
107
108 return (
109 <div className={rowClass}>
110 <dt className={css({ color: "fg.muted", fontSize: "sm" })}>{label}</dt>
111 <dd
112 className={css({
113 margin: "0",
114 color: "fg.default",
115 fontSize: "sm",
116 fontWeight: strong ? "semibold" : "medium",
117 textAlign: "end",
118 })}
119 >
120 {value}
121 </dd>
122 </div>
123 );
124 }
125
126 export default function Page() {
127 const [approvedIds, setApprovedIds] = useState<string[]>([]);
128 const [approvingId, setApprovingId] = useState<string | null>(null);
129
130 const pendingCount = data.payments.filter(
131 (payment) => !approvedIds.includes(payment.id),
132 ).length;
133
134 const confirmApproval = (paymentId: string) => {
135 setApprovedIds((current) =>
136 current.includes(paymentId) ? current : [...current, paymentId],
137 );
138 setApprovingId(null);
139 };
140
141 return (
142 <main
143 className={`vektos ${css({
144 minHeight: "full",
145 bg: "bg.canvas",
146 paddingInline: "6",
147 paddingBlock: "8",
148 })}`}
149 >
150 <div className={css({ display: "flex", flexDirection: "column", gap: "6" })}>
151 <div className={css({ display: "flex", flexDirection: "column", gap: "1" })}>
152 <h1
153 className={css({
154 color: "fg.default",
155 fontSize: "lg",
156 fontWeight: "semibold",
157 lineHeight: "tight",
158 })}
159 >
160 Payments awaiting approval
161 </h1>
162 <p className={css({ color: "fg.muted", fontSize: "sm" })}>
163 {pendingCount} of {data.payments.length} payments still need an approval.
164 </p>
165 </div>
166
167 <Card>
168 <CardHeader>
169 <CardTitle>Company payments</CardTitle>
170 <CardDescription>
171 Amounts in {data.currency}. The scheme fee is added on top of the amount.
172 </CardDescription>
173 </CardHeader>
174 <Table
175 aria-label="Company payments waiting for approval"
176 className={css({ marginBlockStart: "4" })}
177 >
178 <TableHead>
179 <TableRow>
180 <TableHeader>Beneficiary</TableHeader>
181 <TableHeader>IBAN</TableHeader>
182 <TableHeader>Due date</TableHeader>
183 <TableHeader numeric>Amount ({data.currency})</TableHeader>
184 <TableHeader>Status</TableHeader>
185 <TableHeader>Action</TableHeader>
186 </TableRow>
187 </TableHead>
188 <TableBody>
189 {data.payments.map((payment) => {
190 const isApproved = approvedIds.includes(payment.id);
191 const fee = feeFor(payment.scheme);
192 const total = payment.amount + fee;
193
194 return (
195 <TableRow key={payment.id}>
196 <TableCell>{payment.beneficiary}</TableCell>
197 <TableCell
198 className={css({ fontSize: "sm", fontVariantNumeric: "tabular-nums" })}
199 >
200 {payment.iban}
201 </TableCell>
202 <TableCell>{formatDueDate(payment.dueDate)}</TableCell>
203 <TableCell numeric>{formatAmount(payment.amount)}</TableCell>
204 <TableCell>
205 {isApproved ? (
206 <Badge tone="success">Approved</Badge>
207 ) : (
208 <Badge tone="warning">Awaiting approval</Badge>
209 )}
210 </TableCell>
211 <TableCell>
212 {isApproved ? null : (
213 <Dialog
214 open={approvingId === payment.id}
215 onOpenChange={(details) =>
216 setApprovingId(details.open ? payment.id : null)
217 }
218 >
219 <DialogTrigger asChild>
220 <Button variant="outline" size="sm">
221 Approve
222 </Button>
223 </DialogTrigger>
224 <DialogContent
225 title={`Approve payment to ${payment.beneficiary}?`}
226 description="Check the details below. Confirming releases the payment."
227 >
228 <dl
229 className={css({
230 display: "flex",
231 flexDirection: "column",
232 gap: "3",
233 margin: "0",
234 })}
235 >
236 <SummaryRow
237 label="Beneficiary"
238 value={payment.beneficiary}
239 />
240 <SummaryRow label="IBAN" value={payment.iban} />
241 <SummaryRow
242 label={`Amount (${data.currency})`}
243 value={formatMoney(payment.amount)}
244 />
245 <SummaryRow
246 label={`Fee (${schemeLabel(payment.scheme)})`}
247 value={formatMoney(fee)}
248 />
249 <SummaryRow
250 label="Total"
251 value={formatMoney(total)}
252 strong
253 divider
254 />
255 </dl>
256 <DialogFooter>
257 <DialogClose asChild>
258 <Button variant="outline">Cancel</Button>
259 </DialogClose>
260 <Button onClick={() => confirmApproval(payment.id)}>
261 Confirm
262 </Button>
263 </DialogFooter>
264 </DialogContent>
265 </Dialog>
266 )}
267 </TableCell>
268 </TableRow>
269 );
270 })}
271 </TableBody>
272 </Table>
273 </Card>
274 </div>
275 </main>
276 );
277 }
278
get_component, list_tokens
4 write_file 1,878 7,776 $0.0099
5 check_code 7,883 1,841 $0.0046