@ai-matrx/agents 0.20.6 → 0.21.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,891 @@
1
+ "use client";
2
+
3
+ // context/react/ContextRulesTable.tsx
4
+ import {
5
+ Switch,
6
+ Tooltip as Tooltip2,
7
+ TooltipContent as TooltipContent2,
8
+ TooltipProvider,
9
+ TooltipTrigger as TooltipTrigger2,
10
+ cn as cn2
11
+ } from "@ai-matrx/design-system";
12
+
13
+ // context/index.ts
14
+ var DEFAULT_INLINE_MAX_CHARS = 200;
15
+ var DEFAULT_INLINE_CAP = 5e4;
16
+ var isNum = (v) => typeof v === "number" && Number.isFinite(v);
17
+ var isValidLimit = (v) => typeof v === "number" && Number.isInteger(v) && v >= 0;
18
+ function resolveContextRule(input) {
19
+ const agent = input.agent ?? null;
20
+ const surface = input.surface ?? null;
21
+ const user = input.user ?? null;
22
+ const cap = isNum(input.cap) ? input.cap : DEFAULT_INLINE_CAP;
23
+ const agentDeclared = agent?.declared === true;
24
+ let include = true;
25
+ let includeBy = "default";
26
+ if (surface?.declared === true && surface.auto_context === false) {
27
+ if (agentDeclared) {
28
+ include = true;
29
+ includeBy = "agent";
30
+ } else {
31
+ include = false;
32
+ includeBy = "page";
33
+ }
34
+ }
35
+ if (agent?.kill_switch === true && !agentDeclared) {
36
+ include = false;
37
+ includeBy = "agent";
38
+ }
39
+ if (user && typeof user.include === "boolean") {
40
+ include = user.include;
41
+ includeBy = "you";
42
+ }
43
+ let limit = isNum(input.default_max) ? input.default_max : DEFAULT_INLINE_MAX_CHARS;
44
+ let limitBy = "default";
45
+ const a = agentDeclared && isNum(agent?.max_inline_chars) ? agent.max_inline_chars : null;
46
+ const s = isNum(surface?.max_inline_chars) ? surface.max_inline_chars : null;
47
+ if (a !== null && s !== null) {
48
+ if (s < a) {
49
+ limit = s;
50
+ limitBy = "page";
51
+ } else {
52
+ limit = a;
53
+ limitBy = "agent";
54
+ }
55
+ } else if (a !== null) {
56
+ limit = a;
57
+ limitBy = "agent";
58
+ } else if (s !== null) {
59
+ limit = s;
60
+ limitBy = "page";
61
+ }
62
+ if (user && isValidLimit(user.max_inline_chars)) {
63
+ limit = user.max_inline_chars;
64
+ limitBy = "you";
65
+ }
66
+ const clamped = limit > cap;
67
+ limit = Math.min(limit, cap);
68
+ const chars = input.chars;
69
+ const delivery = !include ? "off" : chars === null || chars === void 0 || limit === 0 || chars > limit ? "on_request" : "inline";
70
+ return {
71
+ include,
72
+ max_inline_chars: limit,
73
+ delivery,
74
+ decided_by: { include: includeBy, max_inline_chars: limitBy },
75
+ clamped
76
+ };
77
+ }
78
+ function formatChars(n) {
79
+ if (n === null || n === void 0 || !Number.isFinite(n)) return "\u2014";
80
+ const abs = Math.abs(n);
81
+ const trim = (s) => s.replace(/\.0$/, "");
82
+ if (abs < 1e3) return String(Math.round(n));
83
+ if (abs < 1e5) return `${trim((n / 1e3).toFixed(1))}k`;
84
+ if (abs < 1e6) return `${Math.round(n / 1e3)}k`;
85
+ return `${trim((n / 1e6).toFixed(1))}M`;
86
+ }
87
+
88
+ // context/react/icons.tsx
89
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
90
+ function icon(children) {
91
+ return function Icon(props) {
92
+ return /* @__PURE__ */ jsx(
93
+ "svg",
94
+ {
95
+ xmlns: "http://www.w3.org/2000/svg",
96
+ viewBox: "0 0 24 24",
97
+ fill: "none",
98
+ stroke: "currentColor",
99
+ strokeWidth: 2,
100
+ strokeLinecap: "round",
101
+ strokeLinejoin: "round",
102
+ "aria-hidden": "true",
103
+ ...props,
104
+ children
105
+ }
106
+ );
107
+ };
108
+ }
109
+ var EyeIcon = icon(
110
+ /* @__PURE__ */ jsxs(Fragment, { children: [
111
+ /* @__PURE__ */ jsx("path", { d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0" }),
112
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "3" })
113
+ ] })
114
+ );
115
+ var EyeOffIcon = icon(
116
+ /* @__PURE__ */ jsxs(Fragment, { children: [
117
+ /* @__PURE__ */ jsx("path", { d: "M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49" }),
118
+ /* @__PURE__ */ jsx("path", { d: "M14.084 14.158a3 3 0 0 1-4.242-4.242" }),
119
+ /* @__PURE__ */ jsx("path", { d: "M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143" }),
120
+ /* @__PURE__ */ jsx("path", { d: "m2 2 20 20" })
121
+ ] })
122
+ );
123
+ var RotateCcwIcon = icon(
124
+ /* @__PURE__ */ jsxs(Fragment, { children: [
125
+ /* @__PURE__ */ jsx("path", { d: "M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" }),
126
+ /* @__PURE__ */ jsx("path", { d: "M3 3v5h5" })
127
+ ] })
128
+ );
129
+ var PanelRightIcon = icon(
130
+ /* @__PURE__ */ jsxs(Fragment, { children: [
131
+ /* @__PURE__ */ jsx("rect", { width: "18", height: "18", x: "3", y: "3", rx: "2" }),
132
+ /* @__PURE__ */ jsx("path", { d: "M15 3v18" })
133
+ ] })
134
+ );
135
+ var ChevronLeftIcon = icon(/* @__PURE__ */ jsx("path", { d: "m15 18-6-6 6-6" }));
136
+ var TriangleAlertIcon = icon(
137
+ /* @__PURE__ */ jsxs(Fragment, { children: [
138
+ /* @__PURE__ */ jsx("path", { d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" }),
139
+ /* @__PURE__ */ jsx("path", { d: "M12 9v4" }),
140
+ /* @__PURE__ */ jsx("path", { d: "M12 17h.01" })
141
+ ] })
142
+ );
143
+ var SearchIcon = icon(
144
+ /* @__PURE__ */ jsxs(Fragment, { children: [
145
+ /* @__PURE__ */ jsx("circle", { cx: "11", cy: "11", r: "8" }),
146
+ /* @__PURE__ */ jsx("path", { d: "m21 21-4.3-4.3" })
147
+ ] })
148
+ );
149
+ var ArrowDownToLineIcon = icon(
150
+ /* @__PURE__ */ jsxs(Fragment, { children: [
151
+ /* @__PURE__ */ jsx("path", { d: "M12 17V3" }),
152
+ /* @__PURE__ */ jsx("path", { d: "m6 11 6 6 6-6" }),
153
+ /* @__PURE__ */ jsx("path", { d: "M19 21H5" })
154
+ ] })
155
+ );
156
+
157
+ // context/react/InlineMaxInput.tsx
158
+ import * as React from "react";
159
+ import {
160
+ Input,
161
+ Tooltip,
162
+ TooltipContent,
163
+ TooltipTrigger,
164
+ cn
165
+ } from "@ai-matrx/design-system";
166
+
167
+ // context/react/shared.ts
168
+ var LAYER_LABEL = {
169
+ default: "Default",
170
+ page: "Page",
171
+ agent: "Agent",
172
+ you: "You"
173
+ };
174
+ var DELIVERY_LABEL = {
175
+ inline: "Inline",
176
+ on_request: "On request",
177
+ off: "Off"
178
+ };
179
+ function formatLimit(n) {
180
+ return n === 0 ? "Never" : String(n);
181
+ }
182
+ function inheritedLimit(row, cap) {
183
+ return resolveContextRule({ ...row.layers ?? {}, chars: row.chars, cap, user: null }).max_inline_chars;
184
+ }
185
+ function hasOverride(row) {
186
+ return row.userRule !== null && Object.keys(row.userRule).length > 0;
187
+ }
188
+ function withInclude(row, include) {
189
+ return { ...row.userRule ?? {}, include };
190
+ }
191
+ function withLimit(row, limit) {
192
+ const next = { ...row.userRule ?? {} };
193
+ if (limit === null) delete next.max_inline_chars;
194
+ else next.max_inline_chars = limit;
195
+ return Object.keys(next).length === 0 ? null : next;
196
+ }
197
+ function rowId(row) {
198
+ return `${row.surfaceKey}::${row.key}`;
199
+ }
200
+ function show(field, v) {
201
+ if (v === null || v === void 0) return "none";
202
+ if (typeof v === "boolean") return v ? "On" : "Off";
203
+ if (typeof v === "number") return formatLimit(v);
204
+ if (field === "delivery" || field === "missing") {
205
+ return DELIVERY_LABEL[v] ?? String(v);
206
+ }
207
+ if (typeof v === "object") {
208
+ const r = v;
209
+ const parts = [];
210
+ if (r.include !== void 0) parts.push(r.include ? "On" : "Off");
211
+ if (r.max_inline_chars !== void 0) parts.push(formatLimit(r.max_inline_chars));
212
+ return parts.join(", ") || "none";
213
+ }
214
+ return String(v);
215
+ }
216
+ var FIELD_LABEL = {
217
+ include: "Include",
218
+ max_inline_chars: "Inline max",
219
+ delivery: "Delivery",
220
+ user_rule: "Your rule",
221
+ missing: "Not sent"
222
+ };
223
+ function describeMismatches(list) {
224
+ const text = list.map(
225
+ (m) => m.field === "missing" ? "Missing from the server's receipt" : `${FIELD_LABEL[m.field]}: expected ${show(m.field, m.expected)}, got ${show(m.field, m.actual)}`
226
+ ).join(" \xB7 ");
227
+ return text.length > 140 ? `${text.slice(0, 139)}\u2026` : text;
228
+ }
229
+ function onRequestReason(row) {
230
+ if (row.chars === null) return "Size unknown \u2014 the agent reads it on request";
231
+ if (row.max_inline_chars === 0) return "Never inline \u2014 the agent reads it on request";
232
+ return "Over the limit \u2014 the agent reads it on request";
233
+ }
234
+
235
+ // context/react/InlineMaxInput.tsx
236
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
237
+ function InlineMaxInput({
238
+ value,
239
+ inherited,
240
+ cap,
241
+ onCommit,
242
+ disabled,
243
+ label,
244
+ comfortable
245
+ }) {
246
+ const [focused, setFocused] = React.useState(false);
247
+ const [draft, setDraft] = React.useState("");
248
+ const [notice, setNotice] = React.useState(false);
249
+ const skip = React.useRef(false);
250
+ React.useEffect(() => {
251
+ if (!notice) return;
252
+ const t = setTimeout(() => setNotice(false), 2e3);
253
+ return () => clearTimeout(t);
254
+ }, [notice]);
255
+ const commit = () => {
256
+ const text = draft.trim();
257
+ let next;
258
+ if (text === "") next = null;
259
+ else if (/^never$/i.test(text)) next = 0;
260
+ else if (/^\d+$/.test(text)) next = Number(text);
261
+ else return;
262
+ if (next !== null && next > cap) {
263
+ next = cap;
264
+ setNotice(true);
265
+ }
266
+ if (next !== value) onCommit(next);
267
+ };
268
+ const overridden = value !== null;
269
+ return /* @__PURE__ */ jsxs2("div", { className: "flex items-center justify-end gap-1", children: [
270
+ /* @__PURE__ */ jsx2(
271
+ "span",
272
+ {
273
+ "aria-hidden": "true",
274
+ className: cn("h-1.5 w-1.5 shrink-0 rounded-full", overridden ? "bg-primary" : "bg-transparent")
275
+ }
276
+ ),
277
+ /* @__PURE__ */ jsxs2(Tooltip, { open: notice, children: [
278
+ /* @__PURE__ */ jsx2(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx2(
279
+ Input,
280
+ {
281
+ type: "text",
282
+ inputMode: "numeric",
283
+ "aria-label": `Inline max for ${label}`,
284
+ disabled,
285
+ value: focused ? draft : overridden ? formatLimit(value) : "",
286
+ placeholder: overridden ? void 0 : formatLimit(inherited),
287
+ onFocus: () => {
288
+ setDraft(overridden ? String(value) : "");
289
+ setFocused(true);
290
+ },
291
+ onChange: (e) => setDraft(e.target.value),
292
+ onBlur: () => {
293
+ setFocused(false);
294
+ if (skip.current) {
295
+ skip.current = false;
296
+ return;
297
+ }
298
+ commit();
299
+ },
300
+ onKeyDown: (e) => {
301
+ if (e.key === "Enter") e.currentTarget.blur();
302
+ else if (e.key === "Escape") {
303
+ e.stopPropagation();
304
+ skip.current = true;
305
+ e.currentTarget.blur();
306
+ }
307
+ },
308
+ className: cn(
309
+ "w-[6.5ch] min-w-0 rounded px-1 py-0 text-right tabular-nums shadow-none",
310
+ comfortable ? "h-8 text-base" : "h-6 text-xs"
311
+ )
312
+ }
313
+ ) }),
314
+ /* @__PURE__ */ jsx2(TooltipContent, { children: `Limit is ${cap}` })
315
+ ] }),
316
+ overridden && !disabled ? /* @__PURE__ */ jsxs2(Tooltip, { children: [
317
+ /* @__PURE__ */ jsx2(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx2(
318
+ "button",
319
+ {
320
+ type: "button",
321
+ "aria-label": `Reset inline max for ${label}`,
322
+ onClick: () => onCommit(null),
323
+ className: cn(
324
+ "inline-flex shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground",
325
+ comfortable ? "h-8 w-8" : "h-5 w-5"
326
+ ),
327
+ children: /* @__PURE__ */ jsx2(RotateCcwIcon, { className: "h-3 w-3" })
328
+ }
329
+ ) }),
330
+ /* @__PURE__ */ jsx2(TooltipContent, { children: `Reset to ${formatLimit(inherited)}` })
331
+ ] }) : /* @__PURE__ */ jsx2("span", { "aria-hidden": "true", className: cn("shrink-0", comfortable ? "w-8" : "w-5") })
332
+ ] });
333
+ }
334
+
335
+ // context/react/ContextRulesTable.tsx
336
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
337
+ var GROUPS = [
338
+ { origin: "page", label: "Page" },
339
+ { origin: "attached", label: "Attached" },
340
+ { origin: "system", label: "System" }
341
+ ];
342
+ var GRID = {
343
+ compact: "grid grid-cols-[minmax(0,1fr)_2.75rem_4rem_6.5rem] items-center gap-x-2 px-2",
344
+ comfortable: "grid grid-cols-[minmax(0,1fr)_3rem_4.5rem_9rem] items-center gap-x-2 px-3"
345
+ };
346
+ function ContextRulesTable({
347
+ rows,
348
+ cap,
349
+ readOnly,
350
+ mismatches,
351
+ onChange,
352
+ onOpenRow,
353
+ density = "compact",
354
+ selectedKey,
355
+ className
356
+ }) {
357
+ const comfortable = density === "comfortable";
358
+ const present = GROUPS.filter((g) => rows.some((r) => r.origin === g.origin));
359
+ const grouped = present.length > 1;
360
+ return /* @__PURE__ */ jsx3(TooltipProvider, { delayDuration: 300, titleTooltips: false, children: /* @__PURE__ */ jsxs3("div", { role: "table", "aria-label": "Context", "data-density": density, className: cn2("text-xs", className), children: [
361
+ /* @__PURE__ */ jsxs3(
362
+ "div",
363
+ {
364
+ role: "row",
365
+ className: cn2(
366
+ GRID[density],
367
+ "sticky top-0 z-10 h-7 border-b border-border bg-card font-medium text-muted-foreground"
368
+ ),
369
+ children: [
370
+ /* @__PURE__ */ jsx3("span", { role: "columnheader", children: "Item" }),
371
+ /* @__PURE__ */ jsx3("span", { role: "columnheader", className: "text-center", children: "Include" }),
372
+ /* @__PURE__ */ jsx3("span", { role: "columnheader", className: "text-right", children: "Chars" }),
373
+ /* @__PURE__ */ jsx3("span", { role: "columnheader", className: "pr-6 text-right", children: "Inline max" })
374
+ ]
375
+ }
376
+ ),
377
+ rows.length === 0 ? /* @__PURE__ */ jsx3("div", { className: "px-2 py-3 text-center text-muted-foreground", children: "Nothing in context" }) : present.map((g) => /* @__PURE__ */ jsxs3("div", { role: "rowgroup", "aria-label": grouped ? g.label : void 0, children: [
378
+ grouped ? /* @__PURE__ */ jsx3(
379
+ "div",
380
+ {
381
+ role: "row",
382
+ className: "flex h-6 items-center bg-muted/40 px-2 font-medium text-muted-foreground",
383
+ children: /* @__PURE__ */ jsx3("span", { role: "cell", children: g.label })
384
+ }
385
+ ) : null,
386
+ rows.filter((r) => r.origin === g.origin).map((row) => /* @__PURE__ */ jsx3(
387
+ ContextRuleRow,
388
+ {
389
+ row,
390
+ cap,
391
+ density,
392
+ readOnly,
393
+ selected: selectedKey === row.key,
394
+ mismatches: mismatches?.filter((m) => m.key === row.key) ?? [],
395
+ onChange,
396
+ onOpenRow,
397
+ comfortable
398
+ },
399
+ rowId(row)
400
+ ))
401
+ ] }, g.origin))
402
+ ] }) });
403
+ }
404
+ function ContextRuleRow({
405
+ row,
406
+ cap,
407
+ density,
408
+ comfortable,
409
+ readOnly,
410
+ selected,
411
+ mismatches,
412
+ onChange,
413
+ onOpenRow
414
+ }) {
415
+ const decided = `Include: ${LAYER_LABEL[row.decided_by.include]} \xB7 Limit: ${LAYER_LABEL[row.decided_by.max_inline_chars]}`;
416
+ const labelNode = onOpenRow ? /* @__PURE__ */ jsx3(
417
+ "button",
418
+ {
419
+ type: "button",
420
+ onClick: () => onOpenRow(row.key),
421
+ className: "min-w-0 truncate text-left hover:underline focus-visible:underline focus-visible:outline-none",
422
+ children: row.label
423
+ }
424
+ ) : /* @__PURE__ */ jsx3("span", { className: "min-w-0 truncate", children: row.label });
425
+ return /* @__PURE__ */ jsxs3(
426
+ "div",
427
+ {
428
+ role: "row",
429
+ "data-key": row.key,
430
+ "data-included": row.include ? "true" : "false",
431
+ "data-mismatch": mismatches.length > 0 ? "true" : void 0,
432
+ "aria-selected": selected || void 0,
433
+ className: cn2(
434
+ GRID[density],
435
+ "border-b border-border/50",
436
+ comfortable ? "min-h-11" : "h-7",
437
+ selected && "bg-accent"
438
+ ),
439
+ children: [
440
+ /* @__PURE__ */ jsxs3("div", { role: "cell", className: cn2("flex min-w-0 items-center gap-1.5", !row.include && "opacity-50"), children: [
441
+ mismatches.length > 0 ? /* @__PURE__ */ jsxs3(Tooltip2, { children: [
442
+ /* @__PURE__ */ jsx3(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ jsx3(
443
+ "span",
444
+ {
445
+ role: "img",
446
+ "aria-label": "Mismatch",
447
+ className: "inline-flex shrink-0 text-warning",
448
+ children: /* @__PURE__ */ jsx3(TriangleAlertIcon, { className: "h-3.5 w-3.5" })
449
+ }
450
+ ) }),
451
+ /* @__PURE__ */ jsx3(TooltipContent2, { children: describeMismatches(mismatches) })
452
+ ] }) : null,
453
+ /* @__PURE__ */ jsxs3(Tooltip2, { children: [
454
+ /* @__PURE__ */ jsx3(TooltipTrigger2, { asChild: true, children: labelNode }),
455
+ /* @__PURE__ */ jsxs3(TooltipContent2, { children: [
456
+ /* @__PURE__ */ jsx3("div", { children: row.label }),
457
+ /* @__PURE__ */ jsx3("div", { className: "font-normal text-muted-foreground", children: decided })
458
+ ] })
459
+ ] }),
460
+ comfortable ? /* @__PURE__ */ jsx3("span", { className: "ml-auto shrink-0 rounded bg-muted px-1 text-[0.6875rem] leading-4 text-muted-foreground", children: LAYER_LABEL[row.decided_by.max_inline_chars] }) : null
461
+ ] }),
462
+ /* @__PURE__ */ jsx3("div", { role: "cell", className: "flex justify-center", children: /* @__PURE__ */ jsx3(
463
+ Switch,
464
+ {
465
+ size: "sm",
466
+ "aria-label": `Include ${row.label}`,
467
+ checked: row.include,
468
+ disabled: readOnly,
469
+ onCheckedChange: (next) => onChange(row.key, row.surfaceKey, withInclude(row, next))
470
+ }
471
+ ) }),
472
+ /* @__PURE__ */ jsxs3(
473
+ "div",
474
+ {
475
+ role: "cell",
476
+ className: cn2("flex items-center justify-end gap-1 tabular-nums", !row.include && "opacity-50"),
477
+ children: [
478
+ row.include && row.delivery === "on_request" ? /* @__PURE__ */ jsxs3(Tooltip2, { children: [
479
+ /* @__PURE__ */ jsx3(TooltipTrigger2, { asChild: true, children: /* @__PURE__ */ jsx3("span", { role: "img", "aria-label": "On request", className: "inline-flex text-muted-foreground", children: /* @__PURE__ */ jsx3(ArrowDownToLineIcon, { className: "h-3 w-3" }) }) }),
480
+ /* @__PURE__ */ jsx3(TooltipContent2, { children: onRequestReason(row) })
481
+ ] }) : null,
482
+ /* @__PURE__ */ jsx3("span", { children: formatChars(row.chars) })
483
+ ]
484
+ }
485
+ ),
486
+ /* @__PURE__ */ jsx3("div", { role: "cell", children: /* @__PURE__ */ jsx3(
487
+ InlineMaxInput,
488
+ {
489
+ label: row.label,
490
+ value: row.userRule?.max_inline_chars ?? null,
491
+ inherited: inheritedLimit(row, cap),
492
+ cap,
493
+ disabled: readOnly,
494
+ comfortable,
495
+ onCommit: (next) => onChange(row.key, row.surfaceKey, withLimit(row, next))
496
+ }
497
+ ) })
498
+ ]
499
+ }
500
+ );
501
+ }
502
+
503
+ // context/react/ContextRulesChip.tsx
504
+ import * as React2 from "react";
505
+ import {
506
+ BottomSheet,
507
+ Popover,
508
+ PopoverContent,
509
+ PopoverTrigger,
510
+ Switch as Switch2,
511
+ Tooltip as Tooltip3,
512
+ TooltipContent as TooltipContent3,
513
+ TooltipProvider as TooltipProvider2,
514
+ TooltipTrigger as TooltipTrigger3,
515
+ cn as cn3
516
+ } from "@ai-matrx/design-system";
517
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
518
+ function summarize(rows) {
519
+ let count = 0;
520
+ let chars = 0;
521
+ for (const r of rows) {
522
+ if (!r.include) continue;
523
+ count += 1;
524
+ chars += r.chars ?? 0;
525
+ }
526
+ return { count, chars };
527
+ }
528
+ function IconButton({
529
+ label,
530
+ onClick,
531
+ comfortable,
532
+ children
533
+ }) {
534
+ return /* @__PURE__ */ jsxs4(Tooltip3, { children: [
535
+ /* @__PURE__ */ jsx4(TooltipTrigger3, { asChild: true, children: /* @__PURE__ */ jsx4(
536
+ "button",
537
+ {
538
+ type: "button",
539
+ "aria-label": label,
540
+ onClick,
541
+ className: cn3(
542
+ "inline-flex shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground",
543
+ comfortable ? "h-11 w-11" : "h-7 w-7"
544
+ ),
545
+ children
546
+ }
547
+ ) }),
548
+ /* @__PURE__ */ jsx4(TooltipContent3, { children: label })
549
+ ] });
550
+ }
551
+ function ContextRulesChip({
552
+ label,
553
+ rows,
554
+ cap,
555
+ on,
556
+ onToggleAll,
557
+ onChange,
558
+ onResetAll,
559
+ onOpenFullView,
560
+ mismatchCount = 0,
561
+ mismatches,
562
+ onOpenRow,
563
+ isMobile,
564
+ readOnly,
565
+ open: openProp,
566
+ onOpenChange,
567
+ className
568
+ }) {
569
+ const [openState, setOpenState] = React2.useState(false);
570
+ const open = openProp ?? openState;
571
+ const setOpen = (next) => {
572
+ if (openProp === void 0) setOpenState(next);
573
+ onOpenChange?.(next);
574
+ };
575
+ const { count, chars } = summarize(rows);
576
+ const anyOverride = rows.some(hasOverride);
577
+ const warn = mismatchCount > 0;
578
+ const comfortable = !!isMobile;
579
+ const face = /* @__PURE__ */ jsxs4(
580
+ "button",
581
+ {
582
+ type: "button",
583
+ "aria-label": `Context: ${label}`,
584
+ "data-mismatch": warn ? "true" : void 0,
585
+ onClick: isMobile ? () => setOpen(true) : void 0,
586
+ className: cn3(
587
+ "inline-flex h-7 max-w-[14rem] items-center gap-1.5 rounded-full border border-border bg-card px-2 text-xs text-foreground hover:bg-accent",
588
+ !on && "text-muted-foreground",
589
+ warn && "border-warning/60 ring-1 ring-warning",
590
+ className
591
+ ),
592
+ children: [
593
+ on ? /* @__PURE__ */ jsx4(EyeIcon, { className: "h-3.5 w-3.5 shrink-0" }) : /* @__PURE__ */ jsx4(EyeOffIcon, { className: "h-3.5 w-3.5 shrink-0" }),
594
+ /* @__PURE__ */ jsx4("span", { className: "min-w-0 truncate", children: label }),
595
+ /* @__PURE__ */ jsx4("span", { className: "shrink-0 tabular-nums text-muted-foreground", children: count }),
596
+ warn ? /* @__PURE__ */ jsxs4("span", { className: "inline-flex shrink-0 items-center gap-0.5 tabular-nums text-warning", children: [
597
+ /* @__PURE__ */ jsx4(TriangleAlertIcon, { className: "h-3 w-3" }),
598
+ mismatchCount
599
+ ] }) : null
600
+ ]
601
+ }
602
+ );
603
+ const body = /* @__PURE__ */ jsxs4("div", { className: "flex min-h-0 flex-col", children: [
604
+ /* @__PURE__ */ jsxs4(
605
+ "div",
606
+ {
607
+ className: cn3(
608
+ "flex shrink-0 items-center gap-2 border-b border-border px-3",
609
+ comfortable ? "h-12" : "h-10"
610
+ ),
611
+ children: [
612
+ on ? /* @__PURE__ */ jsx4(EyeIcon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }) : /* @__PURE__ */ jsx4(EyeOffIcon, { className: "h-4 w-4 shrink-0 text-muted-foreground" }),
613
+ /* @__PURE__ */ jsx4("span", { className: "min-w-0 truncate text-sm font-medium", children: label }),
614
+ /* @__PURE__ */ jsx4("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", children: `${count} \xB7 ${formatChars(chars)} chars` }),
615
+ /* @__PURE__ */ jsxs4("div", { className: "ml-auto flex shrink-0 items-center gap-0.5", children: [
616
+ /* @__PURE__ */ jsx4(
617
+ Switch2,
618
+ {
619
+ size: "sm",
620
+ "aria-label": "Page context",
621
+ checked: on,
622
+ disabled: readOnly,
623
+ onCheckedChange: onToggleAll,
624
+ className: "mr-1"
625
+ }
626
+ ),
627
+ anyOverride && !readOnly ? /* @__PURE__ */ jsx4(IconButton, { label: "Reset all", onClick: onResetAll, comfortable, children: /* @__PURE__ */ jsx4(RotateCcwIcon, { className: "h-3.5 w-3.5" }) }) : null,
628
+ /* @__PURE__ */ jsx4(
629
+ IconButton,
630
+ {
631
+ label: "Open full view",
632
+ comfortable,
633
+ onClick: () => {
634
+ setOpen(false);
635
+ onOpenFullView();
636
+ },
637
+ children: /* @__PURE__ */ jsx4(PanelRightIcon, { className: "h-3.5 w-3.5" })
638
+ }
639
+ )
640
+ ] })
641
+ ]
642
+ }
643
+ ),
644
+ /* @__PURE__ */ jsx4("div", { className: cn3("min-h-0 overflow-y-auto", comfortable ? "max-h-[70dvh]" : "max-h-[min(24rem,60vh)]"), children: /* @__PURE__ */ jsx4(
645
+ ContextRulesTable,
646
+ {
647
+ rows,
648
+ cap,
649
+ readOnly,
650
+ density: comfortable ? "comfortable" : "compact",
651
+ onChange,
652
+ ...mismatches ? { mismatches } : {},
653
+ ...onOpenRow ? { onOpenRow } : {}
654
+ }
655
+ ) })
656
+ ] });
657
+ if (isMobile) {
658
+ return /* @__PURE__ */ jsxs4(TooltipProvider2, { delayDuration: 300, titleTooltips: false, children: [
659
+ face,
660
+ /* @__PURE__ */ jsx4(BottomSheet, { open, onOpenChange: setOpen, title: label, surface: "solid", children: body })
661
+ ] });
662
+ }
663
+ return /* @__PURE__ */ jsx4(TooltipProvider2, { delayDuration: 300, titleTooltips: false, children: /* @__PURE__ */ jsxs4(Popover, { open, onOpenChange: setOpen, children: [
664
+ /* @__PURE__ */ jsx4(PopoverTrigger, { asChild: true, children: face }),
665
+ /* @__PURE__ */ jsx4(
666
+ PopoverContent,
667
+ {
668
+ align: "start",
669
+ className: "w-[26rem] max-w-[calc(100vw-1rem)] overflow-hidden p-0",
670
+ children: body
671
+ }
672
+ )
673
+ ] }) });
674
+ }
675
+
676
+ // context/react/ContextRulesPanelBody.tsx
677
+ import * as React3 from "react";
678
+ import {
679
+ Input as Input2,
680
+ Switch as Switch3,
681
+ TooltipProvider as TooltipProvider3,
682
+ cn as cn4
683
+ } from "@ai-matrx/design-system";
684
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
685
+ function layerCells(row) {
686
+ const { surface, agent, default_max } = row.layers ?? {};
687
+ const declared = agent?.declared === true;
688
+ const pageOff = surface?.declared === true && surface.auto_context === false;
689
+ const num = (n) => typeof n === "number" ? formatLimit(n) : "\u2014";
690
+ const rule = row.userRule;
691
+ return {
692
+ default: { include: "On", limit: formatLimit(default_max ?? DEFAULT_INLINE_MAX_CHARS) },
693
+ page: { include: pageOff ? "Off" : "\u2014", limit: num(surface?.max_inline_chars) },
694
+ agent: {
695
+ include: agent?.kill_switch && !declared ? "Off" : declared && pageOff ? "On" : "\u2014",
696
+ limit: declared ? num(agent?.max_inline_chars) : "\u2014"
697
+ },
698
+ you: {
699
+ include: rule?.include === void 0 ? "\u2014" : rule.include ? "On" : "Off",
700
+ limit: num(rule?.max_inline_chars)
701
+ }
702
+ };
703
+ }
704
+ var LAYERS = ["default", "page", "agent", "you"];
705
+ function LayerTable({ row }) {
706
+ const cells = layerCells(row);
707
+ const cell = (text, winning) => /* @__PURE__ */ jsx5(
708
+ "span",
709
+ {
710
+ role: "cell",
711
+ "data-winning": winning ? "true" : void 0,
712
+ className: cn4(
713
+ "rounded px-1.5 py-0.5 text-right tabular-nums",
714
+ winning ? "bg-primary/10 font-medium text-foreground" : "text-muted-foreground"
715
+ ),
716
+ children: text
717
+ }
718
+ );
719
+ return /* @__PURE__ */ jsxs5("div", { role: "table", "aria-label": "Layers", className: "text-xs", children: [
720
+ /* @__PURE__ */ jsxs5(
721
+ "div",
722
+ {
723
+ role: "row",
724
+ className: "grid h-7 grid-cols-[1fr_5rem_5rem] items-center gap-x-2 border-b border-border font-medium text-muted-foreground",
725
+ children: [
726
+ /* @__PURE__ */ jsx5("span", { role: "columnheader", children: "Layer" }),
727
+ /* @__PURE__ */ jsx5("span", { role: "columnheader", className: "text-right", children: "Include" }),
728
+ /* @__PURE__ */ jsx5("span", { role: "columnheader", className: "text-right", children: "Inline max" })
729
+ ]
730
+ }
731
+ ),
732
+ LAYERS.map((layer) => /* @__PURE__ */ jsxs5(
733
+ "div",
734
+ {
735
+ role: "row",
736
+ className: "grid h-7 grid-cols-[1fr_5rem_5rem] items-center gap-x-2 border-b border-border/50",
737
+ children: [
738
+ /* @__PURE__ */ jsx5("span", { role: "cell", children: LAYER_LABEL[layer] }),
739
+ cell(cells[layer].include, row.decided_by.include === layer),
740
+ cell(cells[layer].limit, row.decided_by.max_inline_chars === layer)
741
+ ]
742
+ },
743
+ layer
744
+ ))
745
+ ] });
746
+ }
747
+ function RowDetail({
748
+ row,
749
+ cap,
750
+ readOnly,
751
+ mismatches,
752
+ onChange,
753
+ renderDetail,
754
+ comfortable
755
+ }) {
756
+ return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-3 p-3", children: [
757
+ /* @__PURE__ */ jsxs5("div", { className: "flex min-w-0 items-baseline gap-2", children: [
758
+ /* @__PURE__ */ jsx5("h3", { className: "min-w-0 truncate text-sm font-medium", children: row.label }),
759
+ /* @__PURE__ */ jsx5("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", children: `${formatChars(row.chars)} chars \xB7 ${DELIVERY_LABEL[row.delivery]}` })
760
+ ] }),
761
+ mismatches.length > 0 ? /* @__PURE__ */ jsxs5("div", { className: "flex items-start gap-1.5 rounded-md border border-warning/40 bg-warning/10 px-2 py-1.5 text-xs text-warning", children: [
762
+ /* @__PURE__ */ jsx5(TriangleAlertIcon, { className: "mt-0.5 h-3.5 w-3.5 shrink-0" }),
763
+ /* @__PURE__ */ jsx5("span", { children: describeMismatches(mismatches) })
764
+ ] }) : null,
765
+ /* @__PURE__ */ jsxs5("div", { className: "grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2 text-xs", children: [
766
+ /* @__PURE__ */ jsx5("span", { className: "text-muted-foreground", children: "Include" }),
767
+ /* @__PURE__ */ jsx5("div", { className: cn4("flex items-center", comfortable ? "h-11" : "h-7"), children: /* @__PURE__ */ jsx5(
768
+ Switch3,
769
+ {
770
+ size: "sm",
771
+ "aria-label": `Include ${row.label}`,
772
+ checked: row.include,
773
+ disabled: readOnly,
774
+ onCheckedChange: (next) => onChange(row.key, row.surfaceKey, withInclude(row, next))
775
+ }
776
+ ) }),
777
+ /* @__PURE__ */ jsx5("span", { className: "text-muted-foreground", children: "Inline max" }),
778
+ /* @__PURE__ */ jsx5("div", { className: "flex", children: /* @__PURE__ */ jsx5(
779
+ InlineMaxInput,
780
+ {
781
+ label: row.label,
782
+ value: row.userRule?.max_inline_chars ?? null,
783
+ inherited: inheritedLimit(row, cap),
784
+ cap,
785
+ disabled: readOnly,
786
+ comfortable,
787
+ onCommit: (next) => onChange(row.key, row.surfaceKey, withLimit(row, next))
788
+ }
789
+ ) })
790
+ ] }),
791
+ /* @__PURE__ */ jsx5(LayerTable, { row }),
792
+ renderDetail ? renderDetail(row) : null
793
+ ] });
794
+ }
795
+ function ContextRulesPanelBody({
796
+ rows,
797
+ cap,
798
+ mismatches,
799
+ readOnly,
800
+ onChange,
801
+ renderDetail,
802
+ isMobile,
803
+ selectedKey: selectedProp,
804
+ onSelectedKeyChange,
805
+ className
806
+ }) {
807
+ const [selectedState, setSelectedState] = React3.useState(null);
808
+ const [query, setQuery] = React3.useState("");
809
+ const selectedKey = selectedProp !== void 0 ? selectedProp : selectedState;
810
+ const select = (key) => {
811
+ if (selectedProp === void 0) setSelectedState(key);
812
+ onSelectedKeyChange?.(key);
813
+ };
814
+ const q = query.trim().toLowerCase();
815
+ const visible = q ? rows.filter((r) => r.label.toLowerCase().includes(q) || r.key.toLowerCase().includes(q)) : rows;
816
+ const selected = selectedKey ? rows.find((r) => r.key === selectedKey) ?? null : null;
817
+ const comfortable = !!isMobile;
818
+ const search = /* @__PURE__ */ jsxs5("div", { className: "relative shrink-0 border-b border-border p-2", children: [
819
+ /* @__PURE__ */ jsx5(SearchIcon, { className: "pointer-events-none absolute left-4 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" }),
820
+ /* @__PURE__ */ jsx5(
821
+ Input2,
822
+ {
823
+ type: "search",
824
+ "aria-label": "Search context",
825
+ placeholder: "Search",
826
+ value: query,
827
+ onChange: (e) => setQuery(e.target.value),
828
+ className: cn4("pl-7 shadow-none", comfortable ? "h-11 text-base" : "h-8 text-xs")
829
+ }
830
+ )
831
+ ] });
832
+ const table = /* @__PURE__ */ jsx5("div", { className: "min-h-0 flex-1 overflow-y-auto", children: /* @__PURE__ */ jsx5(
833
+ ContextRulesTable,
834
+ {
835
+ rows: visible,
836
+ cap,
837
+ readOnly,
838
+ density: comfortable ? "comfortable" : "compact",
839
+ selectedKey,
840
+ onChange,
841
+ onOpenRow: (key) => select(key),
842
+ ...mismatches ? { mismatches } : {}
843
+ }
844
+ ) });
845
+ const detail = selected ? /* @__PURE__ */ jsx5(
846
+ RowDetail,
847
+ {
848
+ row: selected,
849
+ cap,
850
+ readOnly,
851
+ mismatches: mismatches?.filter((m) => m.key === selected.key) ?? [],
852
+ onChange,
853
+ renderDetail,
854
+ comfortable
855
+ }
856
+ ) : null;
857
+ if (isMobile) {
858
+ return /* @__PURE__ */ jsx5(TooltipProvider3, { delayDuration: 300, titleTooltips: false, children: /* @__PURE__ */ jsx5("div", { className: cn4("flex h-full min-h-0 flex-col", className), children: selected ? /* @__PURE__ */ jsxs5(Fragment2, { children: [
859
+ /* @__PURE__ */ jsx5("div", { className: "flex h-12 shrink-0 items-center border-b border-border px-1", children: /* @__PURE__ */ jsxs5(
860
+ "button",
861
+ {
862
+ type: "button",
863
+ onClick: () => select(null),
864
+ className: "inline-flex h-11 items-center gap-1 rounded-md px-2 text-sm text-muted-foreground hover:text-foreground",
865
+ children: [
866
+ /* @__PURE__ */ jsx5(ChevronLeftIcon, { className: "h-4 w-4" }),
867
+ "Back"
868
+ ]
869
+ }
870
+ ) }),
871
+ /* @__PURE__ */ jsx5("div", { className: "min-h-0 flex-1 overflow-y-auto", children: detail })
872
+ ] }) : /* @__PURE__ */ jsxs5(Fragment2, { children: [
873
+ search,
874
+ table
875
+ ] }) }) });
876
+ }
877
+ return /* @__PURE__ */ jsx5(TooltipProvider3, { delayDuration: 300, titleTooltips: false, children: /* @__PURE__ */ jsxs5("div", { className: cn4("flex h-full min-h-0", className), children: [
878
+ /* @__PURE__ */ jsxs5("aside", { className: "flex w-[22rem] shrink-0 flex-col border-r border-border", children: [
879
+ search,
880
+ table
881
+ ] }),
882
+ /* @__PURE__ */ jsx5("section", { className: "min-h-0 min-w-0 flex-1 overflow-y-auto", children: detail ?? /* @__PURE__ */ jsx5("div", { className: "flex h-full items-center justify-center text-xs text-muted-foreground", children: "Select an item" }) })
883
+ ] }) });
884
+ }
885
+ export {
886
+ ContextRulesChip,
887
+ ContextRulesPanelBody,
888
+ ContextRulesTable,
889
+ InlineMaxInput
890
+ };
891
+ //# sourceMappingURL=index.js.map