@ai-matrx/agents 0.21.3 → 0.21.4
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.
- package/CHANGELOG.md +33 -2
- package/dist/content-transfer/index.cjs.map +1 -1
- package/dist/content-transfer/index.js.map +1 -1
- package/dist/content-transfer/react/index.cjs.map +1 -1
- package/dist/content-transfer/react/index.js.map +1 -1
- package/dist/context/index.cjs +77 -7
- package/dist/context/index.cjs.map +1 -1
- package/dist/context/index.d.cts +29 -1
- package/dist/context/index.d.ts +29 -1
- package/dist/context/index.js +77 -7
- package/dist/context/index.js.map +1 -1
- package/dist/context/react/index.cjs +24 -11
- package/dist/context/react/index.cjs.map +1 -1
- package/dist/context/react/index.d.cts +6 -4
- package/dist/context/react/index.d.ts +6 -4
- package/dist/context/react/index.js +24 -11
- package/dist/context/react/index.js.map +1 -1
- package/dist/mandates/index.cjs +2 -2
- package/dist/mandates/index.cjs.map +1 -1
- package/dist/mandates/index.d.cts +4 -4
- package/dist/mandates/index.d.ts +4 -4
- package/dist/mandates/index.js +2 -2
- package/dist/mandates/index.js.map +1 -1
- package/mandates/snapshots/keys.0.21.4.json +652 -0
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../context/react/index.ts","../../../context/react/ContextRulesTable.tsx","../../../context/index.ts","../../../context/react/icons.tsx","../../../context/react/InlineMaxInput.tsx","../../../context/react/shared.ts","../../../context/react/ContextRulesChip.tsx","../../../context/react/ContextRulesPanelBody.tsx"],"sourcesContent":["/**\n * @ai-matrx/agents/context/react — presentational, state-agnostic context\n * rules UI. Every edit leaves through `onChange`; the host owns persistence\n * (RULES.md §3: optimistic write, no debounce). SSR-safe: no window access at\n * import. Built on @ai-matrx/design-system primitives; glyphs are inlined\n * Lucide shapes (C19).\n */\nexport { ContextRulesTable, type ContextRulesTableProps, type ContextRulesDensity } from \"./ContextRulesTable\";\nexport { ContextRulesChip, type ContextRulesChipProps } from \"./ContextRulesChip\";\nexport { ContextRulesPanelBody, type ContextRulesPanelBodyProps } from \"./ContextRulesPanelBody\";\nexport { InlineMaxInput, type InlineMaxInputProps } from \"./InlineMaxInput\";\n","import * as React from \"react\";\nimport {\n Switch,\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n cn,\n} from \"@ai-matrx/design-system\";\n\nimport {\n formatChars,\n type ContextReceiptMismatch,\n type ContextRowOrigin,\n type ResolvedContextRow,\n type SavedContextRule,\n} from \"../index\";\nimport { ArrowDownToLineIcon, TriangleAlertIcon } from \"./icons\";\nimport { InlineMaxInput } from \"./InlineMaxInput\";\nimport {\n LAYER_LABEL,\n describeMismatches,\n inheritedLimit,\n onRequestReason,\n rowId,\n withInclude,\n withLimit,\n} from \"./shared\";\n\nexport type ContextRulesDensity = \"compact\" | \"comfortable\";\n\nexport interface ContextRulesTableProps {\n rows: readonly ResolvedContextRow[];\n cap: number;\n readOnly?: boolean | undefined;\n /** From `compareReceipt` — rows with a mismatch get an amber marker. */\n mismatches?: readonly ContextReceiptMismatch[];\n /** `next === null` resets the person's rule for that key. */\n onChange: (key: string, surfaceKey: string, next: SavedContextRule | null) => void;\n onOpenRow?: (key: string) => void;\n /** `comfortable` = 44px touch rows. Default `compact`. */\n density?: ContextRulesDensity;\n /** Highlights the open row (master/detail). */\n selectedKey?: string | null;\n className?: string;\n}\n\nconst GROUPS: Array<{ origin: ContextRowOrigin; label: string }> = [\n { origin: \"page\", label: \"Page\" },\n { origin: \"attached\", label: \"Attached\" },\n { origin: \"system\", label: \"System\" },\n];\n\nconst GRID = {\n compact: \"grid grid-cols-[minmax(0,1fr)_2.75rem_4rem_6.5rem] items-center gap-x-2 px-2\",\n comfortable: \"grid grid-cols-[minmax(0,1fr)_3rem_4.5rem_9rem] items-center gap-x-2 px-3\",\n} as const;\n\n/**\n * The context rules table: Item | Include | Chars | Inline max. Presentational\n * and state-agnostic — every edit goes out through `onChange`.\n */\nexport function ContextRulesTable({\n rows,\n cap,\n readOnly,\n mismatches,\n onChange,\n onOpenRow,\n density = \"compact\",\n selectedKey,\n className,\n}: ContextRulesTableProps) {\n const comfortable = density === \"comfortable\";\n const present = GROUPS.filter((g) => rows.some((r) => r.origin === g.origin));\n const grouped = present.length > 1;\n\n return (\n <TooltipProvider delayDuration={300} titleTooltips={false}>\n <div role=\"table\" aria-label=\"Context\" data-density={density} className={cn(\"text-xs\", className)}>\n <div\n role=\"row\"\n className={cn(\n GRID[density],\n \"sticky top-0 z-10 h-7 border-b border-border bg-card font-medium text-muted-foreground\",\n )}\n >\n <span role=\"columnheader\">Item</span>\n <span role=\"columnheader\" className=\"text-center\">\n Include\n </span>\n <span role=\"columnheader\" className=\"text-right\">\n Chars\n </span>\n <span role=\"columnheader\" className=\"pr-6 text-right\">\n Inline max\n </span>\n </div>\n {rows.length === 0 ? (\n <div className=\"px-2 py-3 text-center text-muted-foreground\">Nothing in context</div>\n ) : (\n present.map((g) => (\n <div role=\"rowgroup\" key={g.origin} aria-label={grouped ? g.label : undefined}>\n {grouped ? (\n <div\n role=\"row\"\n className=\"flex h-6 items-center bg-muted/40 px-2 font-medium text-muted-foreground\"\n >\n <span role=\"cell\">{g.label}</span>\n </div>\n ) : null}\n {rows\n .filter((r) => r.origin === g.origin)\n .map((row) => (\n <ContextRuleRow\n key={rowId(row)}\n row={row}\n cap={cap}\n density={density}\n readOnly={readOnly}\n selected={selectedKey === row.key}\n mismatches={mismatches?.filter((m) => m.key === row.key) ?? []}\n onChange={onChange}\n onOpenRow={onOpenRow}\n comfortable={comfortable}\n />\n ))}\n </div>\n ))\n )}\n </div>\n </TooltipProvider>\n );\n}\n\ninterface RowProps {\n row: ResolvedContextRow;\n cap: number;\n density: ContextRulesDensity;\n comfortable: boolean;\n readOnly: boolean | undefined;\n selected: boolean;\n mismatches: ContextReceiptMismatch[];\n onChange: ContextRulesTableProps[\"onChange\"];\n onOpenRow: ContextRulesTableProps[\"onOpenRow\"];\n}\n\nfunction ContextRuleRow({\n row,\n cap,\n density,\n comfortable,\n readOnly,\n selected,\n mismatches,\n onChange,\n onOpenRow,\n}: RowProps) {\n const decided = `Include: ${LAYER_LABEL[row.decided_by.include]} · Limit: ${LAYER_LABEL[row.decided_by.max_inline_chars]}`;\n const labelNode = onOpenRow ? (\n <button\n type=\"button\"\n onClick={() => onOpenRow(row.key)}\n className=\"min-w-0 truncate text-left hover:underline focus-visible:underline focus-visible:outline-none\"\n >\n {row.label}\n </button>\n ) : (\n <span className=\"min-w-0 truncate\">{row.label}</span>\n );\n\n return (\n <div\n role=\"row\"\n data-key={row.key}\n data-included={row.include ? \"true\" : \"false\"}\n data-mismatch={mismatches.length > 0 ? \"true\" : undefined}\n aria-selected={selected || undefined}\n className={cn(\n GRID[density],\n \"border-b border-border/50\",\n comfortable ? \"min-h-11\" : \"h-7\",\n selected && \"bg-accent\",\n )}\n >\n <div role=\"cell\" className={cn(\"flex min-w-0 items-center gap-1.5\", !row.include && \"opacity-50\")}>\n {mismatches.length > 0 ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <span\n role=\"img\"\n aria-label=\"Mismatch\"\n className=\"inline-flex shrink-0 text-warning\"\n >\n <TriangleAlertIcon className=\"h-3.5 w-3.5\" />\n </span>\n </TooltipTrigger>\n <TooltipContent>{describeMismatches(mismatches)}</TooltipContent>\n </Tooltip>\n ) : null}\n <Tooltip>\n <TooltipTrigger asChild>{labelNode}</TooltipTrigger>\n <TooltipContent>\n <div>{row.label}</div>\n <div className=\"font-normal text-muted-foreground\">{decided}</div>\n </TooltipContent>\n </Tooltip>\n {comfortable ? (\n <span className=\"ml-auto shrink-0 rounded bg-muted px-1 text-[0.6875rem] leading-4 text-muted-foreground\">\n {LAYER_LABEL[row.decided_by.max_inline_chars]}\n </span>\n ) : null}\n </div>\n <div role=\"cell\" className=\"flex justify-center\">\n <Switch\n size=\"sm\"\n aria-label={`Include ${row.label}`}\n checked={row.include}\n disabled={readOnly}\n onCheckedChange={(next) => onChange(row.key, row.surfaceKey, withInclude(row, next))}\n />\n </div>\n <div\n role=\"cell\"\n className={cn(\"flex items-center justify-end gap-1 tabular-nums\", !row.include && \"opacity-50\")}\n >\n {row.include && row.delivery === \"on_request\" ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <span role=\"img\" aria-label=\"On request\" className=\"inline-flex text-muted-foreground\">\n <ArrowDownToLineIcon className=\"h-3 w-3\" />\n </span>\n </TooltipTrigger>\n <TooltipContent>{onRequestReason(row)}</TooltipContent>\n </Tooltip>\n ) : null}\n <span>{formatChars(row.chars)}</span>\n </div>\n <div role=\"cell\">\n <InlineMaxInput\n label={row.label}\n value={row.userRule?.max_inline_chars ?? null}\n inherited={inheritedLimit(row, cap)}\n cap={cap}\n disabled={readOnly}\n comfortable={comfortable}\n onCommit={(next) => onChange(row.key, row.surfaceKey, withLimit(row, next))}\n />\n </div>\n </div>\n );\n}\n","/**\n * @ai-matrx/agents/context — the context value rules, headless.\n *\n * Contract: common-docs/systems/scopes-context/context-delivery/RULES.md.\n * Parity corpus: ./rules-corpus.json (run here by rules.test.ts and by aidream's\n * pytest against the Python twin `resolve_context_rule`). Every function here\n * is pure, zero-React, and safe to import on a server.\n *\n * The one flow a client runs per turn:\n * rows = values.map(v => resolveContextRow(v, savedRows, cap)) // what the table shows\n * context = buildContextWire(rows) // what the request sends\n * …on `context_receipt`: compareReceipt(rows, receipt) // screen vs server\n */\n\n// ── Constants ───────────────────────────────────────────────────────────────\n\n/** `users.user_surface_state.feature` for the person's saved rules. */\nexport const CONTEXT_RULES_FEATURE = \"context_rules\";\n/** Surface key for values no surface emitted (attachments, server-added values). */\nexport const DEFAULT_SURFACE_KEY = \"_default\";\n/** The server's default inline threshold when no layer sets one. */\nexport const DEFAULT_INLINE_MAX_CHARS = 200;\n/** The default ceiling every resolved limit is clamped to (a server knob). */\nexport const DEFAULT_INLINE_CAP = 50000;\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\n/** Which layer decided a field — lowest to highest. */\nexport type ContextLayer = \"default\" | \"page\" | \"agent\" | \"you\";\nexport type ContextDelivery = \"inline\" | \"on_request\" | \"off\";\n\n/** One saved per-person rule (one key on one surface). Both fields optional. */\nexport interface SavedContextRule {\n include?: boolean;\n max_inline_chars?: number;\n}\n\n/** `{ [surface_key]: { [context key]: SavedContextRule } }` — the person's rows. */\nexport type SavedContextRuleRows = Record<string, Record<string, SavedContextRule>>;\n\n/** The agent layer for one key (RULES.md §2). */\nexport interface ContextAgentLayer {\n /** The agent's Context Policy declares this key (or the value is the agent's own seed). */\n declared?: boolean;\n /** The policy's ceiling; only read when `declared`. */\n max_inline_chars?: number | null;\n /** `auto_context_disabled` — closes every undeclared key. */\n kill_switch?: boolean;\n}\n\n/** The page layer for one key: the surface that emitted the value. */\nexport interface ContextSurfaceLayer {\n /** The surface declares this value (a `ui_surface_value` row / manifest entry). */\n declared?: boolean;\n /** `false` drops the value unless the agent declares it. */\n auto_context?: boolean | null;\n /** `inlineUpTo` / envelope `max_inline_chars` / DB column. */\n max_inline_chars?: number | null;\n}\n\n/** The non-person layers for one value — what the table's layer breakdown shows. */\nexport interface ContextRuleLayers {\n /** The server's per-key default limit; `null`/absent = 200. */\n default_max?: number | null;\n agent?: ContextAgentLayer | null;\n surface?: ContextSurfaceLayer | null;\n}\n\n/**\n * Input to `resolveContextRule`. Snake case on purpose: it is the corpus shape\n * and the Python twin's shape. `user` is typed loosely because invalid saved\n * values (non-boolean include, non-integer or negative limit) must be ignored,\n * not trusted.\n */\nexport interface ContextRuleInput extends ContextRuleLayers {\n /** Size in code points; `null` = an unresolved lazy source. */\n chars: number | null;\n user?: { include?: unknown; max_inline_chars?: unknown } | null;\n /** Ceiling; default `DEFAULT_INLINE_CAP`. */\n cap?: number;\n}\n\nexport interface ContextRuleResult {\n include: boolean;\n /** Effective limit, after the clamp. */\n max_inline_chars: number;\n delivery: ContextDelivery;\n decided_by: { include: ContextLayer; max_inline_chars: ContextLayer };\n clamped: boolean;\n}\n\n/** One receipt row — RULES.md §5, wire fields exactly. */\nexport interface ContextReceiptRow {\n key: string;\n label: string;\n surface_key: string;\n origin: \"client\" | \"server\" | \"surroundings\" | \"rule\";\n chars: number | null;\n include: boolean;\n max_inline_chars: number;\n delivery: ContextDelivery;\n decided_by: { include: ContextLayer; max_inline_chars: ContextLayer };\n user_rule: { include?: boolean; max_inline_chars?: number } | null;\n clamped: boolean;\n /** The CLIENT itself sent a value the person turned off. */\n client_sent_excluded: boolean;\n /** `\"model\"`: nothing reached a model that reads no context. */\n blocked_by: \"model\" | null;\n}\n\n/** The per-turn receipt the server streams as `context_receipt` — RULES.md §5. */\nexport interface ContextReceipt {\n version: 1;\n surface: string | null;\n cap: number;\n /** False: this turn's model cannot read context at all (every row `blocked_by: \"model\"`). */\n model_reads_context: boolean;\n /** The person's saved rules could not be read; the turn ran without them. */\n rules_error: string | null;\n rows: ContextReceiptRow[];\n}\n\nexport type ContextRowOrigin = \"page\" | \"attached\" | \"system\";\n\n/** A client's resolved row: what its table renders and what `buildContextWire` sends. */\nexport interface ResolvedContextRow extends ContextRuleResult {\n key: string;\n label: string;\n surfaceKey: string;\n origin: ContextRowOrigin;\n /** The raw value, or an already-rich envelope (`{ content, type, … }`). */\n value: unknown;\n chars: number | null;\n /** The saved rule that was applied (merged `_default` + surface row), or null. */\n userRule: SavedContextRule | null;\n description?: string;\n /** Context object type for the wire envelope (`text`, `json`, …). */\n type?: string;\n /** The non-person layers the rule was resolved from. Absent = default only. */\n layers?: ContextRuleLayers;\n}\n\n/** What a client knows about one value before resolution. */\nexport interface ContextRowSource {\n key: string;\n label: string;\n surfaceKey?: string;\n origin: ContextRowOrigin;\n value: unknown;\n /** Override the measured size (e.g. `null` for an unresolved lazy source). */\n chars?: number | null;\n description?: string;\n type?: string;\n layers?: ContextRuleLayers;\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────\n\nconst isNum = (v: unknown): v is number => typeof v === \"number\" && Number.isFinite(v);\nconst isValidLimit = (v: unknown): v is number =>\n typeof v === \"number\" && Number.isInteger(v) && v >= 0;\n\n// ── resolveContextRule — RULES.md §2, line for line ─────────────────────────\n\nexport function resolveContextRule(input: ContextRuleInput): ContextRuleResult {\n const agent = input.agent ?? null;\n const surface = input.surface ?? null;\n const user = input.user ?? null;\n const cap = isNum(input.cap) ? input.cap : DEFAULT_INLINE_CAP;\n const agentDeclared = agent?.declared === true;\n\n let include = true;\n let includeBy: ContextLayer = \"default\";\n if (surface?.declared === true && surface.auto_context === false) {\n if (agentDeclared) {\n include = true;\n includeBy = \"agent\";\n } else {\n include = false;\n includeBy = \"page\";\n }\n }\n if (agent?.kill_switch === true && !agentDeclared) {\n include = false;\n includeBy = \"agent\";\n }\n if (user && typeof user.include === \"boolean\") {\n include = user.include;\n includeBy = \"you\";\n }\n\n let limit = isNum(input.default_max) ? input.default_max : DEFAULT_INLINE_MAX_CHARS;\n let limitBy: ContextLayer = \"default\";\n const a = agentDeclared && isNum(agent?.max_inline_chars) ? agent.max_inline_chars : null;\n const s = isNum(surface?.max_inline_chars) ? surface.max_inline_chars : null;\n if (a !== null && s !== null) {\n if (s < a) {\n limit = s;\n limitBy = \"page\";\n } else {\n limit = a;\n limitBy = \"agent\";\n }\n } else if (a !== null) {\n limit = a;\n limitBy = \"agent\";\n } else if (s !== null) {\n limit = s;\n limitBy = \"page\";\n }\n if (user && isValidLimit(user.max_inline_chars)) {\n limit = user.max_inline_chars;\n limitBy = \"you\";\n }\n const clamped = limit > cap;\n limit = Math.min(limit, cap);\n\n const chars = input.chars;\n const delivery: ContextDelivery = !include\n ? \"off\"\n : chars === null || chars === undefined || limit === 0 || chars > limit\n ? \"on_request\"\n : \"inline\";\n\n return {\n include,\n max_inline_chars: limit,\n delivery,\n decided_by: { include: includeBy, max_inline_chars: limitBy },\n clamped,\n };\n}\n\n// ── contextValueChars — RULES.md §1 ─────────────────────────────────────────\n\n/** Count Unicode code points (never UTF-16 units: `\"😀\".length` is 2). */\nfunction codePoints(s: string): number {\n let n = 0;\n for (const _ of s) n += 1;\n return n;\n}\n\n/**\n * Size of a value in code points, exactly as the server's `content_as_str()`:\n * a string is itself; anything else is `JSON.stringify(value, null, 2)`\n * (Python `json.dumps(value, ensure_ascii=False, indent=2)`). `undefined` → 0.\n */\nexport function contextValueChars(value: unknown): number {\n if (value === undefined) return 0;\n if (typeof value === \"string\") return codePoints(value);\n let text: string | undefined;\n try {\n text = JSON.stringify(value, null, 2);\n } catch {\n text = String(value);\n }\n return text === undefined ? 0 : codePoints(text);\n}\n\n// ── lookupSavedRule — RULES.md §3 ───────────────────────────────────────────\n\nfunction sanitizeRule(raw: unknown): SavedContextRule {\n const out: SavedContextRule = {};\n if (!raw || typeof raw !== \"object\") return out;\n const r = raw as Record<string, unknown>;\n if (typeof r.include === \"boolean\") out.include = r.include;\n if (isValidLimit(r.max_inline_chars)) out.max_inline_chars = r.max_inline_chars;\n return out;\n}\n\n/**\n * The person's rule for one key on one surface: `_default[key]` merged per\n * field under `rows[surfaceKey][key]`, invalid fields stripped. `null` when\n * nothing valid is saved.\n */\nexport function lookupSavedRule(\n rows: SavedContextRuleRows | null | undefined,\n surfaceKey: string,\n key: string,\n): SavedContextRule | null {\n if (!rows || typeof rows !== \"object\") return null;\n const base = sanitizeRule(rows[DEFAULT_SURFACE_KEY]?.[key]);\n const own = surfaceKey === DEFAULT_SURFACE_KEY ? {} : sanitizeRule(rows[surfaceKey]?.[key]);\n const merged: SavedContextRule = { ...base, ...own };\n return Object.keys(merged).length === 0 ? null : merged;\n}\n\n// ── resolveContextRow — the glue a client runs per value ────────────────────\n\n/** Resolve one value into the row the table renders and the wire sends. */\nexport function resolveContextRow(\n source: ContextRowSource,\n savedRows: SavedContextRuleRows | null | undefined,\n cap: number = DEFAULT_INLINE_CAP,\n): ResolvedContextRow {\n const surfaceKey = source.surfaceKey ?? DEFAULT_SURFACE_KEY;\n const chars =\n source.chars !== undefined ? source.chars : contextValueChars(envelopeContent(source.value));\n const userRule = lookupSavedRule(savedRows, surfaceKey, source.key);\n const result = resolveContextRule({ ...(source.layers ?? {}), chars, user: userRule, cap });\n const row: ResolvedContextRow = {\n ...result,\n key: source.key,\n label: source.label,\n surfaceKey,\n origin: source.origin,\n value: source.value,\n chars,\n userRule,\n };\n if (source.description !== undefined) row.description = source.description;\n if (source.type !== undefined) row.type = source.type;\n if (source.layers !== undefined) row.layers = source.layers;\n return row;\n}\n\n// ── buildContextWire — the ONLY producer of a request's `context` ──────────\n\nfunction isEnvelope(value: unknown): value is Record<string, unknown> {\n return (\n !!value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n Object.prototype.hasOwnProperty.call(value, \"content\")\n );\n}\n\nfunction envelopeContent(value: unknown): unknown {\n return isEnvelope(value) ? value.content : value;\n}\n\n/**\n * Build the request's `context` object from the resolved rows. This is the\n * ONLY function that may produce it, so what the table shows and what the\n * request carries cannot drift apart.\n *\n * - A row whose `include` is false is omitted entirely — it never reaches the\n * wire (RULES.md §1: off means off everywhere).\n * - An included row becomes `{ content, type?, label, description?,\n * max_inline_chars? }`. An already-rich envelope (a value with its own\n * `content`, e.g. a working document carrying `source`/`mutable`/`persist`)\n * keeps every non-rule field it already has; `label`/`description`/`type`\n * are only filled when missing.\n * - `max_inline_chars` on the envelope is the PAGE layer's value only\n * (`layers.surface.max_inline_chars`, else the envelope's own page value).\n * The server reads the person's saved rules itself every turn (RULES.md §3)\n * and the agent layer from its own policy, so the wire must never carry the\n * person's number or the resolved effective limit dressed up as a page rule\n * — that would make a stale client value outrank the server's fresh read.\n */\nexport function buildContextWire(rows: readonly ResolvedContextRow[]): Record<string, unknown> {\n const wire: Record<string, unknown> = {};\n for (const row of rows) {\n if (!row.include) continue;\n const rich = isEnvelope(row.value);\n const envelope: Record<string, unknown> = rich\n ? { ...(row.value as Record<string, unknown>) }\n : { content: row.value };\n delete envelope.max_inline_chars;\n if (envelope.type === undefined && row.type !== undefined) envelope.type = row.type;\n if (envelope.label === undefined) envelope.label = row.label;\n if (envelope.description === undefined && row.description !== undefined) {\n envelope.description = row.description;\n }\n const pageLimit = row.layers?.surface?.max_inline_chars;\n const ownPageLimit = rich ? (row.value as Record<string, unknown>).max_inline_chars : undefined;\n if (isValidLimit(pageLimit)) envelope.max_inline_chars = pageLimit;\n else if (isValidLimit(ownPageLimit)) envelope.max_inline_chars = ownPageLimit;\n wire[row.key] = envelope;\n }\n return wire;\n}\n\n// ── compareReceipt — RULES.md §6 ────────────────────────────────────────────\n\nexport interface ContextReceiptMismatch {\n key: string;\n field: \"include\" | \"max_inline_chars\" | \"delivery\" | \"user_rule\" | \"missing\";\n expected: unknown;\n actual: unknown;\n}\n\nfunction normalizeUserRule(rule: SavedContextRule | null | undefined): SavedContextRule | null {\n const clean = sanitizeRule(rule);\n return Object.keys(clean).length === 0 ? null : clean;\n}\n\nfunction sameRule(a: SavedContextRule | null, b: SavedContextRule | null): boolean {\n if (a === null || b === null) return a === b;\n return a.include === b.include && a.max_inline_chars === b.max_inline_chars;\n}\n\n/**\n * Compare the rows the client resolved (and rendered, and sent) with the\n * receipt the server emitted for the same turn.\n *\n * For each expected row, the receipt row is matched by key + surface key, then\n * by key alone. Compared: `include`, `max_inline_chars`, `delivery` (only when\n * both sides know the size) and `user_rule`. An expected row absent from the\n * receipt is a `missing` mismatch — except a row the client correctly withheld\n * for a reason other than the person's own rule (page `auto_context` off, the\n * agent's kill switch): the client never sent it and the server lists only\n * the person's saved `include: false` rules as `origin: \"rule\"` rows, so its\n * absence is the truth, not a lie. Receipt rows nobody expected are returned\n * as `systemRows` — shown, never hidden.\n */\nexport function compareReceipt(\n expected: readonly ResolvedContextRow[],\n receipt: ContextReceipt,\n): { mismatches: ContextReceiptMismatch[]; systemRows: ContextReceiptRow[] } {\n const mismatches: ContextReceiptMismatch[] = [];\n const used = new Set<ContextReceiptRow>();\n const rows = receipt.rows ?? [];\n\n for (const exp of expected) {\n const actual =\n rows.find((r) => !used.has(r) && r.key === exp.key && r.surface_key === exp.surfaceKey) ??\n rows.find((r) => !used.has(r) && r.key === exp.key);\n if (!actual) {\n const withheldByOthers = !exp.include && exp.decided_by.include !== \"you\";\n if (!withheldByOthers) {\n mismatches.push({ key: exp.key, field: \"missing\", expected: exp.delivery, actual: null });\n }\n continue;\n }\n used.add(actual);\n if (actual.include !== exp.include) {\n mismatches.push({ key: exp.key, field: \"include\", expected: exp.include, actual: actual.include });\n }\n if (actual.max_inline_chars !== exp.max_inline_chars) {\n mismatches.push({\n key: exp.key,\n field: \"max_inline_chars\",\n expected: exp.max_inline_chars,\n actual: actual.max_inline_chars,\n });\n }\n if (exp.chars !== null && actual.chars !== null && actual.delivery !== exp.delivery) {\n mismatches.push({ key: exp.key, field: \"delivery\", expected: exp.delivery, actual: actual.delivery });\n }\n const expRule = normalizeUserRule(exp.userRule);\n const actRule = normalizeUserRule(actual.user_rule);\n if (!sameRule(expRule, actRule)) {\n mismatches.push({ key: exp.key, field: \"user_rule\", expected: expRule, actual: actRule });\n }\n }\n\n return { mismatches, systemRows: rows.filter((r) => !used.has(r)) };\n}\n\n// ── Display ─────────────────────────────────────────────────────────────────\n\n/** Compact size for a tabular column: `950`, `18.4k`, `184k`, `1.2M`, `—` for unknown. */\nexport function formatChars(n: number | null | undefined): string {\n if (n === null || n === undefined || !Number.isFinite(n)) return \"—\";\n const abs = Math.abs(n);\n const trim = (s: string) => s.replace(/\\.0$/, \"\");\n if (abs < 1000) return String(Math.round(n));\n if (abs < 100_000) return `${trim((n / 1000).toFixed(1))}k`;\n if (abs < 1_000_000) return `${Math.round(n / 1000)}k`;\n return `${trim((n / 1_000_000).toFixed(1))}M`;\n}\n","/**\n * Inlined Lucide shapes (C19 — no icon-library dependency): same 24×24 grid,\n * 2px stroke, `currentColor` only. Names match the Lucide originals.\n */\nimport type { ReactNode, SVGProps } from \"react\";\n\nexport type ContextIconProps = SVGProps<SVGSVGElement>;\n\nfunction icon(children: ReactNode) {\n return function Icon(props: ContextIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n {...props}\n >\n {children}\n </svg>\n );\n };\n}\n\nexport const EyeIcon = icon(\n <>\n <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\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </>,\n);\nexport const EyeOffIcon = icon(\n <>\n <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\" />\n <path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\" />\n <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\" />\n <path d=\"m2 2 20 20\" />\n </>,\n);\nexport const RotateCcwIcon = icon(\n <>\n <path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\" />\n <path d=\"M3 3v5h5\" />\n </>,\n);\nexport const PanelRightIcon = icon(\n <>\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" />\n <path d=\"M15 3v18\" />\n </>,\n);\nexport const ChevronLeftIcon = icon(<path d=\"m15 18-6-6 6-6\" />);\nexport const TriangleAlertIcon = icon(\n <>\n <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\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </>,\n);\nexport const SearchIcon = icon(\n <>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </>,\n);\n/** \"On request\" — the agent pulls the value down when it needs it. */\nexport const ArrowDownToLineIcon = icon(\n <>\n <path d=\"M12 17V3\" />\n <path d=\"m6 11 6 6 6-6\" />\n <path d=\"M19 21H5\" />\n </>,\n);\n","import * as React from \"react\";\nimport {\n Input,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n cn,\n} from \"@ai-matrx/design-system\";\n\nimport { RotateCcwIcon } from \"./icons\";\nimport { formatLimit } from \"./shared\";\n\nexport interface InlineMaxInputProps {\n /** The person's own limit, or null when inherited. */\n value: number | null;\n /** What applies without the person's number (shown muted). */\n inherited: number;\n cap: number;\n /** Next limit, or null to drop the person's number. */\n onCommit: (next: number | null) => void;\n disabled?: boolean | undefined;\n /** Accessible name — the row's label. */\n label: string;\n comfortable?: boolean;\n}\n\n/**\n * The Inline max cell: a 6ch numeric field. Inherited value shows as muted\n * placeholder text; an override shows a dot and a reset button. `0` reads\n * \"Never\". Commits on blur/Enter, Escape reverts, above-cap is clamped on\n * commit with a brief \"Limit is {cap}\" tooltip.\n */\nexport function InlineMaxInput({\n value,\n inherited,\n cap,\n onCommit,\n disabled,\n label,\n comfortable,\n}: InlineMaxInputProps) {\n const [focused, setFocused] = React.useState(false);\n const [draft, setDraft] = React.useState(\"\");\n const [notice, setNotice] = React.useState(false);\n const skip = React.useRef(false);\n\n React.useEffect(() => {\n if (!notice) return;\n const t = setTimeout(() => setNotice(false), 2000);\n return () => clearTimeout(t);\n }, [notice]);\n\n const commit = () => {\n const text = draft.trim();\n let next: number | null;\n if (text === \"\") next = null;\n else if (/^never$/i.test(text)) next = 0;\n else if (/^\\d+$/.test(text)) next = Number(text);\n else return;\n if (next !== null && next > cap) {\n next = cap;\n setNotice(true);\n }\n if (next !== value) onCommit(next);\n };\n\n const overridden = value !== null;\n\n return (\n <div className=\"flex items-center justify-end gap-1\">\n <span\n aria-hidden=\"true\"\n className={cn(\"h-1.5 w-1.5 shrink-0 rounded-full\", overridden ? \"bg-primary\" : \"bg-transparent\")}\n />\n <Tooltip open={notice}>\n <TooltipTrigger asChild>\n <Input\n type=\"text\"\n inputMode=\"numeric\"\n aria-label={`Inline max for ${label}`}\n disabled={disabled}\n value={focused ? draft : overridden ? formatLimit(value) : \"\"}\n placeholder={overridden ? undefined : formatLimit(inherited)}\n onFocus={() => {\n setDraft(overridden ? String(value) : \"\");\n setFocused(true);\n }}\n onChange={(e) => setDraft(e.target.value)}\n onBlur={() => {\n setFocused(false);\n if (skip.current) {\n skip.current = false;\n return;\n }\n commit();\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") e.currentTarget.blur();\n else if (e.key === \"Escape\") {\n e.stopPropagation();\n skip.current = true;\n e.currentTarget.blur();\n }\n }}\n className={cn(\n \"w-[6.5ch] min-w-0 rounded px-1 py-0 text-right tabular-nums shadow-none\",\n comfortable ? \"h-8 text-base\" : \"h-6 text-xs\",\n )}\n />\n </TooltipTrigger>\n <TooltipContent>{`Limit is ${cap}`}</TooltipContent>\n </Tooltip>\n {overridden && !disabled ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={`Reset inline max for ${label}`}\n onClick={() => onCommit(null)}\n className={cn(\n \"inline-flex shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground\",\n comfortable ? \"h-8 w-8\" : \"h-5 w-5\",\n )}\n >\n <RotateCcwIcon className=\"h-3 w-3\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>{`Reset to ${formatLimit(inherited)}`}</TooltipContent>\n </Tooltip>\n ) : (\n <span aria-hidden=\"true\" className={cn(\"shrink-0\", comfortable ? \"w-8\" : \"w-5\")} />\n )}\n </div>\n );\n}\n","import {\n resolveContextRule,\n type ContextDelivery,\n type ContextLayer,\n type ContextReceiptMismatch,\n type ResolvedContextRow,\n type SavedContextRule,\n} from \"../index\";\n\nexport const LAYER_LABEL: Record<ContextLayer, string> = {\n default: \"Default\",\n page: \"Page\",\n agent: \"Agent\",\n you: \"You\",\n};\n\nexport const DELIVERY_LABEL: Record<ContextDelivery, string> = {\n inline: \"Inline\",\n on_request: \"On request\",\n off: \"Off\",\n};\n\n/** `0` is \"Never\"; anything else is the number as typed. */\nexport function formatLimit(n: number): string {\n return n === 0 ? \"Never\" : String(n);\n}\n\n/** The limit this row would have without the person's own number. */\nexport function inheritedLimit(row: ResolvedContextRow, cap: number): number {\n return resolveContextRule({ ...(row.layers ?? {}), chars: row.chars, cap, user: null })\n .max_inline_chars;\n}\n\nexport function hasOverride(row: ResolvedContextRow): boolean {\n return row.userRule !== null && Object.keys(row.userRule).length > 0;\n}\n\nexport function withInclude(row: ResolvedContextRow, include: boolean): SavedContextRule {\n return { ...(row.userRule ?? {}), include };\n}\n\nexport function withLimit(row: ResolvedContextRow, limit: number | null): SavedContextRule | null {\n const next: SavedContextRule = { ...(row.userRule ?? {}) };\n if (limit === null) delete next.max_inline_chars;\n else next.max_inline_chars = limit;\n return Object.keys(next).length === 0 ? null : next;\n}\n\nexport function rowId(row: ResolvedContextRow): string {\n return `${row.surfaceKey}::${row.key}`;\n}\n\nfunction show(field: ContextReceiptMismatch[\"field\"], v: unknown): string {\n if (v === null || v === undefined) return \"none\";\n if (typeof v === \"boolean\") return v ? \"On\" : \"Off\";\n if (typeof v === \"number\") return formatLimit(v);\n if (field === \"delivery\" || field === \"missing\") {\n return DELIVERY_LABEL[v as ContextDelivery] ?? String(v);\n }\n if (typeof v === \"object\") {\n const r = v as SavedContextRule;\n const parts: string[] = [];\n if (r.include !== undefined) parts.push(r.include ? \"On\" : \"Off\");\n if (r.max_inline_chars !== undefined) parts.push(formatLimit(r.max_inline_chars));\n return parts.join(\", \") || \"none\";\n }\n return String(v);\n}\n\nconst FIELD_LABEL: Record<ContextReceiptMismatch[\"field\"], string> = {\n include: \"Include\",\n max_inline_chars: \"Inline max\",\n delivery: \"Delivery\",\n user_rule: \"Your rule\",\n missing: \"Not sent\",\n};\n\n/** One line per mismatch — \"Inline max: expected 8000, got 200\". Tooltip-sized. */\nexport function describeMismatches(list: readonly ContextReceiptMismatch[]): string {\n const text = list\n .map((m) =>\n m.field === \"missing\"\n ? \"Missing from the server's receipt\"\n : `${FIELD_LABEL[m.field]}: expected ${show(m.field, m.expected)}, got ${show(m.field, m.actual)}`,\n )\n .join(\" · \");\n return text.length > 140 ? `${text.slice(0, 139)}…` : text;\n}\n\n/** Tooltip for the \"on request\" marker, by why the value is not inline. */\nexport function onRequestReason(row: ResolvedContextRow): string {\n if (row.chars === null) return \"Size unknown — the agent reads it on request\";\n if (row.max_inline_chars === 0) return \"Never inline — the agent reads it on request\";\n return \"Over the limit — the agent reads it on request\";\n}\n","import * as React from \"react\";\nimport {\n BottomSheet,\n Popover,\n PopoverContent,\n PopoverTrigger,\n Switch,\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n cn,\n} from \"@ai-matrx/design-system\";\n\nimport {\n formatChars,\n type ContextReceiptMismatch,\n type ResolvedContextRow,\n type SavedContextRule,\n} from \"../index\";\nimport { ContextRulesTable } from \"./ContextRulesTable\";\nimport { EyeIcon, EyeOffIcon, PanelRightIcon, RotateCcwIcon, TriangleAlertIcon } from \"./icons\";\nimport { hasOverride } from \"./shared\";\n\nexport interface ContextRulesChipProps {\n /** The page's name — \"Notes\", \"Invoice 1042\". */\n label: string;\n rows: readonly ResolvedContextRow[];\n cap: number;\n /** Page context on/off. */\n on: boolean;\n onToggleAll: (next: boolean) => void;\n onChange: (key: string, surfaceKey: string, next: SavedContextRule | null) => void;\n onResetAll: () => void;\n onOpenFullView: () => void;\n mismatchCount?: number;\n mismatches?: readonly ContextReceiptMismatch[];\n onOpenRow?: (key: string) => void;\n /** Bottom sheet instead of a popover. */\n isMobile?: boolean;\n readOnly?: boolean | undefined;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n className?: string;\n}\n\nfunction summarize(rows: readonly ResolvedContextRow[]) {\n let count = 0;\n let chars = 0;\n for (const r of rows) {\n if (!r.include) continue;\n count += 1;\n chars += r.chars ?? 0;\n }\n return { count, chars };\n}\n\nfunction IconButton({\n label,\n onClick,\n comfortable,\n children,\n}: {\n label: string;\n onClick: () => void;\n comfortable: boolean;\n children: React.ReactNode;\n}) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={label}\n onClick={onClick}\n className={cn(\n \"inline-flex shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground\",\n comfortable ? \"h-11 w-11\" : \"h-7 w-7\",\n )}\n >\n {children}\n </button>\n </TooltipTrigger>\n <TooltipContent>{label}</TooltipContent>\n </Tooltip>\n );\n}\n\n/**\n * The composer's context chip and the surface it opens: a header (label,\n * \"N · chars\" summary, page master switch, reset-all, full view) over the\n * compact rules table. Popover on desktop, bottom sheet on mobile.\n */\nexport function ContextRulesChip({\n label,\n rows,\n cap,\n on,\n onToggleAll,\n onChange,\n onResetAll,\n onOpenFullView,\n mismatchCount = 0,\n mismatches,\n onOpenRow,\n isMobile,\n readOnly,\n open: openProp,\n onOpenChange,\n className,\n}: ContextRulesChipProps) {\n const [openState, setOpenState] = React.useState(false);\n const open = openProp ?? openState;\n const setOpen = (next: boolean) => {\n if (openProp === undefined) setOpenState(next);\n onOpenChange?.(next);\n };\n const { count, chars } = summarize(rows);\n const anyOverride = rows.some(hasOverride);\n const warn = mismatchCount > 0;\n const comfortable = !!isMobile;\n\n const face = (\n <button\n type=\"button\"\n aria-label={`Context: ${label}`}\n data-mismatch={warn ? \"true\" : undefined}\n onClick={isMobile ? () => setOpen(true) : undefined}\n className={cn(\n \"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\",\n !on && \"text-muted-foreground\",\n warn && \"border-warning/60 ring-1 ring-warning\",\n className,\n )}\n >\n {on ? <EyeIcon className=\"h-3.5 w-3.5 shrink-0\" /> : <EyeOffIcon className=\"h-3.5 w-3.5 shrink-0\" />}\n <span className=\"min-w-0 truncate\">{label}</span>\n <span className=\"shrink-0 tabular-nums text-muted-foreground\">{count}</span>\n {warn ? (\n <span className=\"inline-flex shrink-0 items-center gap-0.5 tabular-nums text-warning\">\n <TriangleAlertIcon className=\"h-3 w-3\" />\n {mismatchCount}\n </span>\n ) : null}\n </button>\n );\n\n const body = (\n <div className=\"flex min-h-0 flex-col\">\n <div\n className={cn(\n \"flex shrink-0 items-center gap-2 border-b border-border px-3\",\n comfortable ? \"h-12\" : \"h-10\",\n )}\n >\n {on ? (\n <EyeIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n ) : (\n <EyeOffIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n )}\n <span className=\"min-w-0 truncate text-sm font-medium\">{label}</span>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">\n {`${count} · ${formatChars(chars)} chars`}\n </span>\n <div className=\"ml-auto flex shrink-0 items-center gap-0.5\">\n <Switch\n size=\"sm\"\n aria-label=\"Page context\"\n checked={on}\n disabled={readOnly}\n onCheckedChange={onToggleAll}\n className=\"mr-1\"\n />\n {anyOverride && !readOnly ? (\n <IconButton label=\"Reset all\" onClick={onResetAll} comfortable={comfortable}>\n <RotateCcwIcon className=\"h-3.5 w-3.5\" />\n </IconButton>\n ) : null}\n <IconButton\n label=\"Open full view\"\n comfortable={comfortable}\n onClick={() => {\n setOpen(false);\n onOpenFullView();\n }}\n >\n <PanelRightIcon className=\"h-3.5 w-3.5\" />\n </IconButton>\n </div>\n </div>\n <div className={cn(\"min-h-0 overflow-y-auto\", comfortable ? \"max-h-[70dvh]\" : \"max-h-[min(24rem,60vh)]\")}>\n <ContextRulesTable\n rows={rows}\n cap={cap}\n readOnly={readOnly}\n density={comfortable ? \"comfortable\" : \"compact\"}\n onChange={onChange}\n {...(mismatches ? { mismatches } : {})}\n {...(onOpenRow ? { onOpenRow } : {})}\n />\n </div>\n </div>\n );\n\n if (isMobile) {\n return (\n <TooltipProvider delayDuration={300} titleTooltips={false}>\n {face}\n <BottomSheet open={open} onOpenChange={setOpen} title={label} surface=\"solid\">\n {body}\n </BottomSheet>\n </TooltipProvider>\n );\n }\n\n return (\n <TooltipProvider delayDuration={300} titleTooltips={false}>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>{face}</PopoverTrigger>\n <PopoverContent\n align=\"start\"\n className=\"w-[26rem] max-w-[calc(100vw-1rem)] overflow-hidden p-0\"\n >\n {body}\n </PopoverContent>\n </Popover>\n </TooltipProvider>\n );\n}\n","import * as React from \"react\";\nimport {\n Input,\n Switch,\n TooltipProvider,\n cn,\n} from \"@ai-matrx/design-system\";\n\nimport {\n DEFAULT_INLINE_MAX_CHARS,\n formatChars,\n type ContextLayer,\n type ContextReceiptMismatch,\n type ResolvedContextRow,\n type SavedContextRule,\n} from \"../index\";\nimport { ContextRulesTable } from \"./ContextRulesTable\";\nimport { ChevronLeftIcon, SearchIcon, TriangleAlertIcon } from \"./icons\";\nimport { InlineMaxInput } from \"./InlineMaxInput\";\nimport {\n DELIVERY_LABEL,\n LAYER_LABEL,\n describeMismatches,\n formatLimit,\n inheritedLimit,\n withInclude,\n withLimit,\n} from \"./shared\";\n\nexport interface ContextRulesPanelBodyProps {\n rows: readonly ResolvedContextRow[];\n cap: number;\n mismatches?: readonly ContextReceiptMismatch[];\n readOnly?: boolean | undefined;\n onChange: (key: string, surfaceKey: string, next: SavedContextRule | null) => void;\n /** Host content under the built-in controls (a value preview, source link…). */\n renderDetail?: (row: ResolvedContextRow) => React.ReactNode;\n isMobile?: boolean;\n /** Controlled selection; omit for internal state. */\n selectedKey?: string | null;\n onSelectedKeyChange?: (key: string | null) => void;\n className?: string;\n}\n\ninterface LayerCell {\n include: string;\n limit: string;\n}\n\n/** What each layer says about this row; \"—\" where the layer is silent. */\nfunction layerCells(row: ResolvedContextRow): Record<ContextLayer, LayerCell> {\n const { surface, agent, default_max } = row.layers ?? {};\n const declared = agent?.declared === true;\n const pageOff = surface?.declared === true && surface.auto_context === false;\n const num = (n: number | null | undefined) => (typeof n === \"number\" ? formatLimit(n) : \"—\");\n const rule = row.userRule;\n return {\n default: { include: \"On\", limit: formatLimit(default_max ?? DEFAULT_INLINE_MAX_CHARS) },\n page: { include: pageOff ? \"Off\" : \"—\", limit: num(surface?.max_inline_chars) },\n agent: {\n include: agent?.kill_switch && !declared ? \"Off\" : declared && pageOff ? \"On\" : \"—\",\n limit: declared ? num(agent?.max_inline_chars) : \"—\",\n },\n you: {\n include: rule?.include === undefined ? \"—\" : rule.include ? \"On\" : \"Off\",\n limit: num(rule?.max_inline_chars),\n },\n };\n}\n\nconst LAYERS: ContextLayer[] = [\"default\", \"page\", \"agent\", \"you\"];\n\nfunction LayerTable({ row }: { row: ResolvedContextRow }) {\n const cells = layerCells(row);\n const cell = (text: string, winning: boolean) => (\n <span\n role=\"cell\"\n data-winning={winning ? \"true\" : undefined}\n className={cn(\n \"rounded px-1.5 py-0.5 text-right tabular-nums\",\n winning ? \"bg-primary/10 font-medium text-foreground\" : \"text-muted-foreground\",\n )}\n >\n {text}\n </span>\n );\n return (\n <div role=\"table\" aria-label=\"Layers\" className=\"text-xs\">\n <div\n role=\"row\"\n className=\"grid h-7 grid-cols-[1fr_5rem_5rem] items-center gap-x-2 border-b border-border font-medium text-muted-foreground\"\n >\n <span role=\"columnheader\">Layer</span>\n <span role=\"columnheader\" className=\"text-right\">\n Include\n </span>\n <span role=\"columnheader\" className=\"text-right\">\n Inline max\n </span>\n </div>\n {LAYERS.map((layer) => (\n <div\n role=\"row\"\n key={layer}\n className=\"grid h-7 grid-cols-[1fr_5rem_5rem] items-center gap-x-2 border-b border-border/50\"\n >\n <span role=\"cell\">{LAYER_LABEL[layer]}</span>\n {cell(cells[layer].include, row.decided_by.include === layer)}\n {cell(cells[layer].limit, row.decided_by.max_inline_chars === layer)}\n </div>\n ))}\n </div>\n );\n}\n\nfunction RowDetail({\n row,\n cap,\n readOnly,\n mismatches,\n onChange,\n renderDetail,\n comfortable,\n}: {\n row: ResolvedContextRow;\n cap: number;\n readOnly: boolean | undefined;\n mismatches: ContextReceiptMismatch[];\n onChange: ContextRulesPanelBodyProps[\"onChange\"];\n renderDetail: ContextRulesPanelBodyProps[\"renderDetail\"];\n comfortable: boolean;\n}) {\n return (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"flex min-w-0 items-baseline gap-2\">\n <h3 className=\"min-w-0 truncate text-sm font-medium\">{row.label}</h3>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">\n {`${formatChars(row.chars)} chars · ${DELIVERY_LABEL[row.delivery]}`}\n </span>\n </div>\n {mismatches.length > 0 ? (\n <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\">\n <TriangleAlertIcon className=\"mt-0.5 h-3.5 w-3.5 shrink-0\" />\n <span>{describeMismatches(mismatches)}</span>\n </div>\n ) : null}\n <div className=\"grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2 text-xs\">\n <span className=\"text-muted-foreground\">Include</span>\n <div className={cn(\"flex items-center\", comfortable ? \"h-11\" : \"h-7\")}>\n <Switch\n size=\"sm\"\n aria-label={`Include ${row.label}`}\n checked={row.include}\n disabled={readOnly}\n onCheckedChange={(next) => onChange(row.key, row.surfaceKey, withInclude(row, next))}\n />\n </div>\n <span className=\"text-muted-foreground\">Inline max</span>\n <div className=\"flex\">\n <InlineMaxInput\n label={row.label}\n value={row.userRule?.max_inline_chars ?? null}\n inherited={inheritedLimit(row, cap)}\n cap={cap}\n disabled={readOnly}\n comfortable={comfortable}\n onCommit={(next) => onChange(row.key, row.surfaceKey, withLimit(row, next))}\n />\n </div>\n </div>\n <LayerTable row={row} />\n {renderDetail ? renderDetail(row) : null}\n </div>\n );\n}\n\n/**\n * Master/detail body for a docked context panel: search + compact table on\n * the left, the open row's controls, layer breakdown and host detail on the\n * right. On mobile: list, then detail with Back.\n */\nexport function ContextRulesPanelBody({\n rows,\n cap,\n mismatches,\n readOnly,\n onChange,\n renderDetail,\n isMobile,\n selectedKey: selectedProp,\n onSelectedKeyChange,\n className,\n}: ContextRulesPanelBodyProps) {\n const [selectedState, setSelectedState] = React.useState<string | null>(null);\n const [query, setQuery] = React.useState(\"\");\n const selectedKey = selectedProp !== undefined ? selectedProp : selectedState;\n const select = (key: string | null) => {\n if (selectedProp === undefined) setSelectedState(key);\n onSelectedKeyChange?.(key);\n };\n\n const q = query.trim().toLowerCase();\n const visible = q\n ? rows.filter((r) => r.label.toLowerCase().includes(q) || r.key.toLowerCase().includes(q))\n : rows;\n const selected = selectedKey ? rows.find((r) => r.key === selectedKey) ?? null : null;\n const comfortable = !!isMobile;\n\n const search = (\n <div className=\"relative shrink-0 border-b border-border p-2\">\n <SearchIcon className=\"pointer-events-none absolute left-4 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n type=\"search\"\n aria-label=\"Search context\"\n placeholder=\"Search\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n className={cn(\"pl-7 shadow-none\", comfortable ? \"h-11 text-base\" : \"h-8 text-xs\")}\n />\n </div>\n );\n\n const table = (\n <div className=\"min-h-0 flex-1 overflow-y-auto\">\n <ContextRulesTable\n rows={visible}\n cap={cap}\n readOnly={readOnly}\n density={comfortable ? \"comfortable\" : \"compact\"}\n selectedKey={selectedKey}\n onChange={onChange}\n onOpenRow={(key) => select(key)}\n {...(mismatches ? { mismatches } : {})}\n />\n </div>\n );\n\n const detail = selected ? (\n <RowDetail\n row={selected}\n cap={cap}\n readOnly={readOnly}\n mismatches={mismatches?.filter((m) => m.key === selected.key) ?? []}\n onChange={onChange}\n renderDetail={renderDetail}\n comfortable={comfortable}\n />\n ) : null;\n\n if (isMobile) {\n return (\n <TooltipProvider delayDuration={300} titleTooltips={false}>\n <div className={cn(\"flex h-full min-h-0 flex-col\", className)}>\n {selected ? (\n <>\n <div className=\"flex h-12 shrink-0 items-center border-b border-border px-1\">\n <button\n type=\"button\"\n onClick={() => select(null)}\n className=\"inline-flex h-11 items-center gap-1 rounded-md px-2 text-sm text-muted-foreground hover:text-foreground\"\n >\n <ChevronLeftIcon className=\"h-4 w-4\" />\n Back\n </button>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto\">{detail}</div>\n </>\n ) : (\n <>\n {search}\n {table}\n </>\n )}\n </div>\n </TooltipProvider>\n );\n }\n\n return (\n <TooltipProvider delayDuration={300} titleTooltips={false}>\n <div className={cn(\"flex h-full min-h-0\", className)}>\n <aside className=\"flex w-[22rem] shrink-0 flex-col border-r border-border\">\n {search}\n {table}\n </aside>\n <section className=\"min-h-0 min-w-0 flex-1 overflow-y-auto\">\n {detail ?? (\n <div className=\"flex h-full items-center justify-center text-xs text-muted-foreground\">\n Select an item\n </div>\n )}\n </section>\n </div>\n </TooltipProvider>\n );\n}\n"],"mappings":"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","names":["import_design_system","import_jsx_runtime","import_jsx_runtime","React","import_design_system","import_jsx_runtime","React","import_design_system","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../../../context/react/index.ts","../../../context/react/ContextRulesTable.tsx","../../../context/index.ts","../../../context/react/icons.tsx","../../../context/react/InlineMaxInput.tsx","../../../context/react/shared.ts","../../../context/react/ContextRulesChip.tsx","../../../context/react/ContextRulesPanelBody.tsx"],"sourcesContent":["/**\n * @ai-matrx/agents/context/react — presentational, state-agnostic context\n * rules UI. Every edit leaves through `onChange`; the host owns persistence\n * (RULES.md §3: optimistic write, no debounce). SSR-safe: no window access at\n * import. Built on @ai-matrx/design-system primitives; glyphs are inlined\n * Lucide shapes (C19).\n */\nexport { ContextRulesTable, type ContextRulesTableProps, type ContextRulesDensity } from \"./ContextRulesTable\";\nexport { ContextRulesChip, type ContextRulesChipProps } from \"./ContextRulesChip\";\nexport { ContextRulesPanelBody, type ContextRulesPanelBodyProps } from \"./ContextRulesPanelBody\";\nexport { InlineMaxInput, type InlineMaxInputProps } from \"./InlineMaxInput\";\n","import * as React from \"react\";\nimport {\n Switch,\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n cn,\n} from \"@ai-matrx/design-system\";\n\nimport {\n formatChars,\n type ContextReceiptMismatch,\n type ContextRowOrigin,\n type ResolvedContextRow,\n type SavedContextRule,\n} from \"../index\";\nimport { ArrowDownToLineIcon, TriangleAlertIcon } from \"./icons\";\nimport { InlineMaxInput } from \"./InlineMaxInput\";\nimport {\n LAYER_LABEL,\n describeMismatches,\n inheritedLimit,\n onRequestReason,\n rowId,\n withInclude,\n withLimit,\n} from \"./shared\";\n\nexport type ContextRulesDensity = \"compact\" | \"comfortable\";\n\nexport interface ContextRulesTableProps {\n rows: readonly ResolvedContextRow[];\n cap: number;\n readOnly?: boolean | undefined;\n /** From `compareReceipt` — rows with a mismatch get an amber marker. */\n mismatches?: readonly ContextReceiptMismatch[];\n /** `next === null` resets the person's rule for that key. */\n onChange: (key: string, surfaceKey: string, next: SavedContextRule | null) => void;\n onOpenRow?: (key: string) => void;\n /** `comfortable` = 44px touch rows. Default `compact`. */\n density?: ContextRulesDensity;\n /** Highlights the open row (master/detail). */\n selectedKey?: string | null;\n className?: string;\n}\n\nconst GROUPS: Array<{ origin: ContextRowOrigin; label: string }> = [\n { origin: \"page\", label: \"Page\" },\n { origin: \"attached\", label: \"Attached\" },\n { origin: \"system\", label: \"System\" },\n];\n\nconst GRID = {\n compact: \"grid grid-cols-[minmax(0,1fr)_2.75rem_4rem_6.5rem] items-center gap-x-2 px-2\",\n comfortable: \"grid grid-cols-[minmax(0,1fr)_3rem_4.5rem_9rem] items-center gap-x-2 px-3\",\n} as const;\n\n/**\n * The context rules table: Item | Include | Chars | Inline max. Presentational\n * and state-agnostic — every edit goes out through `onChange`.\n */\nexport function ContextRulesTable({\n rows,\n cap,\n readOnly,\n mismatches,\n onChange,\n onOpenRow,\n density = \"compact\",\n selectedKey,\n className,\n}: ContextRulesTableProps) {\n const comfortable = density === \"comfortable\";\n const present = GROUPS.filter((g) => rows.some((r) => r.origin === g.origin));\n const grouped = present.length > 1;\n\n return (\n <TooltipProvider delayDuration={300} titleTooltips={false}>\n <div role=\"table\" aria-label=\"Context\" data-density={density} className={cn(\"text-xs\", className)}>\n <div\n role=\"row\"\n className={cn(\n GRID[density],\n \"sticky top-0 z-10 h-7 border-b border-border bg-card font-medium text-muted-foreground\",\n )}\n >\n <span role=\"columnheader\">Item</span>\n <span role=\"columnheader\" className=\"text-center\">\n Include\n </span>\n <span role=\"columnheader\" className=\"text-right\">\n Chars\n </span>\n <span role=\"columnheader\" className=\"pr-6 text-right\">\n Inline max\n </span>\n </div>\n {rows.length === 0 ? (\n <div className=\"px-2 py-3 text-center text-muted-foreground\">Nothing in context</div>\n ) : (\n present.map((g) => (\n <div role=\"rowgroup\" key={g.origin} aria-label={grouped ? g.label : undefined}>\n {grouped ? (\n <div\n role=\"row\"\n className=\"flex h-6 items-center bg-muted/40 px-2 font-medium text-muted-foreground\"\n >\n <span role=\"cell\">{g.label}</span>\n </div>\n ) : null}\n {rows\n .filter((r) => r.origin === g.origin)\n .map((row) => (\n <ContextRuleRow\n key={rowId(row)}\n row={row}\n cap={cap}\n density={density}\n readOnly={readOnly}\n selected={selectedKey === row.key}\n mismatches={mismatches?.filter((m) => m.key === row.key) ?? []}\n onChange={onChange}\n onOpenRow={onOpenRow}\n comfortable={comfortable}\n />\n ))}\n </div>\n ))\n )}\n </div>\n </TooltipProvider>\n );\n}\n\ninterface RowProps {\n row: ResolvedContextRow;\n cap: number;\n density: ContextRulesDensity;\n comfortable: boolean;\n readOnly: boolean | undefined;\n selected: boolean;\n mismatches: ContextReceiptMismatch[];\n onChange: ContextRulesTableProps[\"onChange\"];\n onOpenRow: ContextRulesTableProps[\"onOpenRow\"];\n}\n\nfunction ContextRuleRow({\n row,\n cap,\n density,\n comfortable,\n readOnly,\n selected,\n mismatches,\n onChange,\n onOpenRow,\n}: RowProps) {\n const decided = `Include: ${LAYER_LABEL[row.decided_by.include]} · Limit: ${LAYER_LABEL[row.decided_by.max_inline_chars]}`;\n const labelNode = onOpenRow ? (\n <button\n type=\"button\"\n onClick={() => onOpenRow(row.key)}\n className=\"min-w-0 truncate text-left hover:underline focus-visible:underline focus-visible:outline-none\"\n >\n {row.label}\n </button>\n ) : (\n <span className=\"min-w-0 truncate\">{row.label}</span>\n );\n\n return (\n <div\n role=\"row\"\n data-key={row.key}\n data-included={row.include ? \"true\" : \"false\"}\n data-mismatch={mismatches.length > 0 ? \"true\" : undefined}\n aria-selected={selected || undefined}\n className={cn(\n GRID[density],\n \"border-b border-border/50\",\n comfortable ? \"min-h-11\" : \"h-7\",\n selected && \"bg-accent\",\n )}\n >\n <div role=\"cell\" className={cn(\"flex min-w-0 items-center gap-1.5\", !row.include && \"opacity-50\")}>\n {mismatches.length > 0 ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <span\n role=\"img\"\n aria-label=\"Mismatch\"\n className=\"inline-flex shrink-0 text-warning\"\n >\n <TriangleAlertIcon className=\"h-3.5 w-3.5\" />\n </span>\n </TooltipTrigger>\n <TooltipContent>{describeMismatches(mismatches)}</TooltipContent>\n </Tooltip>\n ) : null}\n <Tooltip>\n <TooltipTrigger asChild>{labelNode}</TooltipTrigger>\n <TooltipContent>\n <div>{row.label}</div>\n <div className=\"font-normal text-muted-foreground\">{decided}</div>\n </TooltipContent>\n </Tooltip>\n {comfortable ? (\n <span className=\"ml-auto shrink-0 rounded bg-muted px-1 text-[0.6875rem] leading-4 text-muted-foreground\">\n {LAYER_LABEL[row.decided_by.max_inline_chars]}\n </span>\n ) : null}\n </div>\n <div role=\"cell\" className=\"flex justify-center\">\n <Switch\n size=\"sm\"\n aria-label={`Include ${row.label}`}\n checked={row.include}\n disabled={readOnly}\n onCheckedChange={(next) => onChange(row.key, row.surfaceKey, withInclude(row, next))}\n />\n </div>\n <div\n role=\"cell\"\n className={cn(\"flex items-center justify-end gap-1 tabular-nums\", !row.include && \"opacity-50\")}\n >\n {row.include && row.delivery === \"on_request\" ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <span role=\"img\" aria-label=\"On request\" className=\"inline-flex text-muted-foreground\">\n <ArrowDownToLineIcon className=\"h-3 w-3\" />\n </span>\n </TooltipTrigger>\n <TooltipContent>{onRequestReason(row)}</TooltipContent>\n </Tooltip>\n ) : null}\n <span>{formatChars(row.chars)}</span>\n </div>\n <div role=\"cell\">\n <InlineMaxInput\n label={row.label}\n value={row.userRule?.max_inline_chars ?? null}\n inherited={inheritedLimit(row, cap)}\n cap={cap}\n disabled={readOnly}\n comfortable={comfortable}\n onCommit={(next) => onChange(row.key, row.surfaceKey, withLimit(row, next))}\n />\n </div>\n </div>\n );\n}\n","/**\n * @ai-matrx/agents/context — the context value rules, headless.\n *\n * Contract: common-docs/systems/scopes-context/context-delivery/RULES.md.\n * Parity corpus: ./rules-corpus.json (run here by rules.test.ts and by aidream's\n * pytest against the Python twin `resolve_context_rule`). Every function here\n * is pure, zero-React, and safe to import on a server.\n *\n * The one flow a client runs per turn:\n * rows = values.map(v => resolveContextRow(v, savedRows, cap)) // what the table shows\n * context = buildContextWire(rows) // what the request sends\n * …on `context_receipt`: compareReceipt(rows, receipt) // screen vs server\n */\n\n// ── Constants ───────────────────────────────────────────────────────────────\n\n/** `users.user_surface_state.feature` for the person's saved rules. */\nexport const CONTEXT_RULES_FEATURE = \"context_rules\";\n/** Surface key for values no surface emitted (attachments, server-added values). */\nexport const DEFAULT_SURFACE_KEY = \"_default\";\n/** The server's default inline threshold when no layer sets one. */\nexport const DEFAULT_INLINE_MAX_CHARS = 200;\n/** The default ceiling every resolved limit is clamped to (a server knob). */\nexport const DEFAULT_INLINE_CAP = 50000;\n/** A lazy document's server default (RULES.md §2: \"a small lazy document 6000\"). */\nexport const LAZY_SOURCE_DEFAULT_MAX = 6000;\n\n// ── Types ───────────────────────────────────────────────────────────────────\n\n/** Which layer decided a field — lowest to highest. */\nexport type ContextLayer = \"default\" | \"page\" | \"agent\" | \"you\";\nexport type ContextDelivery = \"inline\" | \"on_request\" | \"off\";\n\n/** One saved per-person rule (one key on one surface). Both fields optional. */\nexport interface SavedContextRule {\n include?: boolean;\n max_inline_chars?: number;\n}\n\n/** `{ [surface_key]: { [context key]: SavedContextRule } }` — the person's rows. */\nexport type SavedContextRuleRows = Record<string, Record<string, SavedContextRule>>;\n\n/** The agent layer for one key (RULES.md §2). */\nexport interface ContextAgentLayer {\n /** The agent's Context Policy declares this key (or the value is the agent's own seed). */\n declared?: boolean;\n /** The policy's ceiling; only read when `declared`. */\n max_inline_chars?: number | null;\n /** `auto_context_disabled` — closes every undeclared key. */\n kill_switch?: boolean;\n}\n\n/** The page layer for one key: the surface that emitted the value. */\nexport interface ContextSurfaceLayer {\n /** The surface declares this value (a `ui_surface_value` row / manifest entry). */\n declared?: boolean;\n /** `false` drops the value unless the agent declares it. */\n auto_context?: boolean | null;\n /** `inlineUpTo` / envelope `max_inline_chars` / DB column. */\n max_inline_chars?: number | null;\n}\n\n/** The non-person layers for one value — what the table's layer breakdown shows. */\nexport interface ContextRuleLayers {\n /** The server's per-key default limit; `null`/absent = 200. */\n default_max?: number | null;\n agent?: ContextAgentLayer | null;\n surface?: ContextSurfaceLayer | null;\n}\n\n/**\n * Input to `resolveContextRule`. Snake case on purpose: it is the corpus shape\n * and the Python twin's shape. `user` is typed loosely because invalid saved\n * values (non-boolean include, non-integer or negative limit) must be ignored,\n * not trusted.\n */\nexport interface ContextRuleInput extends ContextRuleLayers {\n /** Size in code points; `null` = an unresolved lazy source. */\n chars: number | null;\n user?: { include?: unknown; max_inline_chars?: unknown } | null;\n /** Ceiling; default `DEFAULT_INLINE_CAP`. */\n cap?: number;\n}\n\nexport interface ContextRuleResult {\n include: boolean;\n /** Effective limit, after the clamp. */\n max_inline_chars: number;\n delivery: ContextDelivery;\n decided_by: { include: ContextLayer; max_inline_chars: ContextLayer };\n clamped: boolean;\n}\n\n/** One receipt row — RULES.md §5, wire fields exactly. */\nexport interface ContextReceiptRow {\n key: string;\n label: string;\n surface_key: string;\n origin: \"client\" | \"server\" | \"surroundings\" | \"rule\";\n chars: number | null;\n include: boolean;\n max_inline_chars: number;\n delivery: ContextDelivery;\n decided_by: { include: ContextLayer; max_inline_chars: ContextLayer };\n user_rule: { include?: boolean; max_inline_chars?: number } | null;\n clamped: boolean;\n /** The CLIENT itself sent a value the person turned off. */\n client_sent_excluded: boolean;\n /** `\"model\"`: nothing reached a model that reads no context. */\n blocked_by: \"model\" | null;\n}\n\n/** The per-turn receipt the server streams as `context_receipt` — RULES.md §5. */\nexport interface ContextReceipt {\n version: 1;\n surface: string | null;\n cap: number;\n /** False: this turn's model cannot read context at all (every row `blocked_by: \"model\"`). */\n model_reads_context: boolean;\n /** The person's saved rules could not be read; the turn ran without them. */\n rules_error: string | null;\n rows: ContextReceiptRow[];\n}\n\nexport type ContextRowOrigin = \"page\" | \"attached\" | \"system\";\n\n/** A client's resolved row: what its table renders and what `buildContextWire` sends. */\nexport interface ResolvedContextRow extends ContextRuleResult {\n key: string;\n label: string;\n surfaceKey: string;\n origin: ContextRowOrigin;\n /** The raw value, or an already-rich envelope (`{ content, type, … }`). */\n value: unknown;\n chars: number | null;\n /** The saved rule that was applied (merged `_default` + surface row), or null. */\n userRule: SavedContextRule | null;\n description?: string;\n /** Context object type for the wire envelope (`text`, `json`, …). */\n type?: string;\n /** The non-person layers the rule was resolved from. Absent = default only. */\n layers?: ContextRuleLayers;\n}\n\n/** What a client knows about one value before resolution. */\nexport interface ContextRowSource {\n key: string;\n label: string;\n surfaceKey?: string;\n origin: ContextRowOrigin;\n value: unknown;\n /** Override the measured size (e.g. `null` for an unresolved lazy source). */\n chars?: number | null;\n description?: string;\n type?: string;\n layers?: ContextRuleLayers;\n}\n\n// ── Helpers ─────────────────────────────────────────────────────────────────\n\nconst isNum = (v: unknown): v is number => typeof v === \"number\" && Number.isFinite(v);\nconst isValidLimit = (v: unknown): v is number =>\n typeof v === \"number\" && Number.isInteger(v) && v >= 0;\n\n// ── resolveContextRule — RULES.md §2, line for line ─────────────────────────\n\nexport function resolveContextRule(input: ContextRuleInput): ContextRuleResult {\n const agent = input.agent ?? null;\n const surface = input.surface ?? null;\n const user = input.user ?? null;\n const cap = isNum(input.cap) ? input.cap : DEFAULT_INLINE_CAP;\n const agentDeclared = agent?.declared === true;\n\n let include = true;\n let includeBy: ContextLayer = \"default\";\n if (surface?.declared === true && surface.auto_context === false) {\n if (agentDeclared) {\n include = true;\n includeBy = \"agent\";\n } else {\n include = false;\n includeBy = \"page\";\n }\n }\n if (agent?.kill_switch === true && !agentDeclared) {\n include = false;\n includeBy = \"agent\";\n }\n if (user && typeof user.include === \"boolean\") {\n include = user.include;\n includeBy = \"you\";\n }\n\n let limit = isNum(input.default_max) ? input.default_max : DEFAULT_INLINE_MAX_CHARS;\n let limitBy: ContextLayer = \"default\";\n const a = agentDeclared && isNum(agent?.max_inline_chars) ? agent.max_inline_chars : null;\n const s = isNum(surface?.max_inline_chars) ? surface.max_inline_chars : null;\n if (a !== null && s !== null) {\n if (s < a) {\n limit = s;\n limitBy = \"page\";\n } else {\n limit = a;\n limitBy = \"agent\";\n }\n } else if (a !== null) {\n limit = a;\n limitBy = \"agent\";\n } else if (s !== null) {\n limit = s;\n limitBy = \"page\";\n }\n if (user && isValidLimit(user.max_inline_chars)) {\n limit = user.max_inline_chars;\n limitBy = \"you\";\n }\n const clamped = limit > cap;\n limit = Math.min(limit, cap);\n\n const chars = input.chars;\n const delivery: ContextDelivery = !include\n ? \"off\"\n : chars === null || chars === undefined || limit === 0 || chars > limit\n ? \"on_request\"\n : \"inline\";\n\n return {\n include,\n max_inline_chars: limit,\n delivery,\n decided_by: { include: includeBy, max_inline_chars: limitBy },\n clamped,\n };\n}\n\n// ── contextValueChars — RULES.md §1 ─────────────────────────────────────────\n\n/** Count Unicode code points (never UTF-16 units: `\"😀\".length` is 2). */\nfunction codePoints(s: string): number {\n let n = 0;\n for (const _ of s) n += 1;\n return n;\n}\n\n/**\n * Size of a value in code points, exactly as the server's `content_as_str()`:\n * a string is itself; anything else is `JSON.stringify(value, null, 2)`\n * (Python `json.dumps(value, ensure_ascii=False, indent=2)`). `undefined` → 0.\n */\nexport function contextValueChars(value: unknown): number {\n if (value === undefined) return 0;\n if (typeof value === \"string\") return codePoints(value);\n let text: string | undefined;\n try {\n text = JSON.stringify(value, null, 2);\n } catch {\n text = String(value);\n }\n return text === undefined ? 0 : codePoints(text);\n}\n\n// ── lookupSavedRule — RULES.md §3 ───────────────────────────────────────────\n\nfunction sanitizeRule(raw: unknown): SavedContextRule {\n const out: SavedContextRule = {};\n if (!raw || typeof raw !== \"object\") return out;\n const r = raw as Record<string, unknown>;\n if (typeof r.include === \"boolean\") out.include = r.include;\n if (isValidLimit(r.max_inline_chars)) out.max_inline_chars = r.max_inline_chars;\n return out;\n}\n\n/**\n * The person's rule for one key on one surface: `_default[key]` merged per\n * field under `rows[surfaceKey][key]`, invalid fields stripped. `null` when\n * nothing valid is saved.\n */\nexport function lookupSavedRule(\n rows: SavedContextRuleRows | null | undefined,\n surfaceKey: string,\n key: string,\n): SavedContextRule | null {\n if (!rows || typeof rows !== \"object\") return null;\n const base = sanitizeRule(rows[DEFAULT_SURFACE_KEY]?.[key]);\n const own = surfaceKey === DEFAULT_SURFACE_KEY ? {} : sanitizeRule(rows[surfaceKey]?.[key]);\n const merged: SavedContextRule = { ...base, ...own };\n return Object.keys(merged).length === 0 ? null : merged;\n}\n\n// ── serverDefaultMax — the server's per-key default, read from the wire value ─\n\n/** The keys that make a dict the rich envelope form (aidream `_RICH_FORM_KEYS`). */\nconst RICH_FORM_KEYS = new Set([\n \"content\",\n \"mutable\",\n \"persist\",\n \"source\",\n \"type\",\n \"label\",\n \"description\",\n \"max_inline_chars\",\n \"default_max_inline_chars\",\n \"summary_agent_id\",\n]);\n\nconst UUID_RE = /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i;\n\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return !!v && typeof v === \"object\" && !Array.isArray(v);\n}\n\n/** A canonical resource reference the server promotes (aidream `parse_resource_reference`). */\nfunction isResourceRef(v: Record<string, unknown>): boolean {\n if (v.__kind !== \"resource_ref\") return false;\n const type = v.resource_type || v.type;\n const id = v.resource_id || v.id;\n return (\n typeof type === \"string\" &&\n type.trim() !== \"\" &&\n typeof id === \"string\" &&\n UUID_RE.test(id.trim())\n );\n}\n\n/**\n * The server's default inline limit for one wire value — the `default` layer\n * the server will use, before page/agent/you. Mirrors aidream\n * `context_rules._server_default_max` over the object `ContextManifest.build`\n * makes from the value (after `normalize_resource_context`):\n *\n * - a rich envelope (every key in the rich-form set, and `content` present or a\n * lazy `source` with a string `kind`) carrying a whole-number, non-negative\n * `default_max_inline_chars` → that;\n * - a top-level resource reference (`__kind: \"resource_ref\"` with a type and a\n * UUID id), or a lazy source whose `extra.resource_type` is set → 0\n * (descriptor-first);\n * - a lazy source (a `source` and null/absent `content`) → 6000;\n * - anything else → null (the server's 200).\n *\n * A resource reference nested as an envelope's `content` is NOT promoted by the\n * server (it reads top-level values only), so it is plain JSON content → null.\n */\nexport function serverDefaultMax(value: unknown): number | null {\n if (!isPlainObject(value)) return null;\n if (isResourceRef(value)) return 0;\n if (!Object.keys(value).every((k) => RICH_FORM_KEYS.has(k))) return null;\n const src = value.source;\n const validSource = isPlainObject(src) && typeof src.kind === \"string\";\n const hasContent = Object.prototype.hasOwnProperty.call(value, \"content\");\n if (!hasContent && !validSource) return null;\n if (isValidLimit(value.default_max_inline_chars)) return value.default_max_inline_chars;\n if (validSource && (value.content === null || value.content === undefined)) {\n const extra = isPlainObject(src.extra) ? src.extra : {};\n return extra.resource_type ? 0 : LAZY_SOURCE_DEFAULT_MAX;\n }\n return null;\n}\n\n// ── resolveContextRow — the glue a client runs per value ────────────────────\n\n/** Resolve one value into the row the table renders and the wire sends. */\nexport function resolveContextRow(\n source: ContextRowSource,\n savedRows: SavedContextRuleRows | null | undefined,\n cap: number = DEFAULT_INLINE_CAP,\n): ResolvedContextRow {\n const surfaceKey = source.surfaceKey ?? DEFAULT_SURFACE_KEY;\n const chars =\n source.chars !== undefined\n ? source.chars\n : isLazySource(source.value)\n ? null\n : contextValueChars(envelopeContent(source.value));\n const userRule = lookupSavedRule(savedRows, surfaceKey, source.key);\n const layers: ContextRuleLayers = { ...(source.layers ?? {}) };\n if (layers.default_max === undefined || layers.default_max === null) {\n const serverDefault = serverDefaultMax(source.value);\n if (serverDefault !== null) layers.default_max = serverDefault;\n }\n const result = resolveContextRule({ ...layers, chars, user: userRule, cap });\n const row: ResolvedContextRow = {\n ...result,\n key: source.key,\n label: source.label,\n surfaceKey,\n origin: source.origin,\n value: source.value,\n chars,\n userRule,\n };\n if (source.description !== undefined) row.description = source.description;\n if (source.type !== undefined) row.type = source.type;\n if (source.layers !== undefined || layers.default_max !== undefined) row.layers = layers;\n return row;\n}\n\n// ── buildContextWire — the ONLY producer of a request's `context` ──────────\n\nfunction isEnvelope(value: unknown): value is Record<string, unknown> {\n return (\n !!value &&\n typeof value === \"object\" &&\n !Array.isArray(value) &&\n Object.prototype.hasOwnProperty.call(value, \"content\")\n );\n}\n\n/** A source-only pointer (body deliberately absent) or a resource reference: size unknown. */\nfunction isLazySource(value: unknown): boolean {\n if (!isPlainObject(value)) return false;\n if (isResourceRef(value)) return true;\n const src = value.source;\n return (\n isPlainObject(src) &&\n typeof src.kind === \"string\" &&\n (value.content === null || value.content === undefined)\n );\n}\n\nfunction envelopeContent(value: unknown): unknown {\n return isEnvelope(value) ? value.content : value;\n}\n\n/**\n * Build the request's `context` object from the resolved rows. This is the\n * ONLY function that may produce it, so what the table shows and what the\n * request carries cannot drift apart.\n *\n * - A row whose `include` is false is omitted entirely — it never reaches the\n * wire (RULES.md §1: off means off everywhere).\n * - An included row becomes `{ content, type?, label, description?,\n * max_inline_chars? }`. An already-rich envelope (a value with its own\n * `content`, e.g. a working document carrying `source`/`mutable`/`persist`)\n * keeps every non-rule field it already has; `label`/`description`/`type`\n * are only filled when missing.\n * - `max_inline_chars` on the envelope is the PAGE layer's value only\n * (`layers.surface.max_inline_chars`, else the envelope's own page value).\n * The server reads the person's saved rules itself every turn (RULES.md §3)\n * and the agent layer from its own policy, so the wire must never carry the\n * person's number or the resolved effective limit dressed up as a page rule\n * — that would make a stale client value outrank the server's fresh read.\n */\nexport function buildContextWire(rows: readonly ResolvedContextRow[]): Record<string, unknown> {\n const wire: Record<string, unknown> = {};\n for (const row of rows) {\n if (!row.include) continue;\n // Rich: an envelope with `content`, or a source-only lazy pointer. Every\n // non-rule field survives — including `default_max_inline_chars`, the\n // server's per-key default (not a person's or a page's number).\n const rich = isEnvelope(row.value) || (isLazySource(row.value) && !isResourceRef(row.value as Record<string, unknown>));\n const envelope: Record<string, unknown> = rich\n ? { ...(row.value as Record<string, unknown>) }\n : { content: row.value };\n delete envelope.max_inline_chars;\n if (envelope.type === undefined && row.type !== undefined) envelope.type = row.type;\n if (envelope.label === undefined) envelope.label = row.label;\n if (envelope.description === undefined && row.description !== undefined) {\n envelope.description = row.description;\n }\n const pageLimit = row.layers?.surface?.max_inline_chars;\n const ownPageLimit = rich ? (row.value as Record<string, unknown>).max_inline_chars : undefined;\n if (isValidLimit(pageLimit)) envelope.max_inline_chars = pageLimit;\n else if (isValidLimit(ownPageLimit)) envelope.max_inline_chars = ownPageLimit;\n wire[row.key] = envelope;\n }\n return wire;\n}\n\n// ── compareReceipt — RULES.md §6 ────────────────────────────────────────────\n\nexport interface ContextReceiptMismatch {\n key: string;\n field: \"include\" | \"max_inline_chars\" | \"delivery\" | \"user_rule\" | \"missing\";\n expected: unknown;\n actual: unknown;\n}\n\nfunction normalizeUserRule(rule: SavedContextRule | null | undefined): SavedContextRule | null {\n const clean = sanitizeRule(rule);\n return Object.keys(clean).length === 0 ? null : clean;\n}\n\nfunction sameRule(a: SavedContextRule | null, b: SavedContextRule | null): boolean {\n if (a === null || b === null) return a === b;\n return a.include === b.include && a.max_inline_chars === b.max_inline_chars;\n}\n\n/**\n * Compare the rows the client resolved (and rendered, and sent) with the\n * receipt the server emitted for the same turn.\n *\n * For each expected row, the receipt row is matched by key + surface key, then\n * by key alone. Compared: `include`, `max_inline_chars`, `delivery` (only when\n * both sides know the size) and `user_rule`. An expected row absent from the\n * receipt is a `missing` mismatch — except a row the client correctly withheld\n * for a reason other than the person's own rule (page `auto_context` off, the\n * agent's kill switch): the client never sent it and the server lists only\n * the person's saved `include: false` rules as `origin: \"rule\"` rows, so its\n * absence is the truth, not a lie. Receipt rows nobody expected are returned\n * as `systemRows` — shown, never hidden.\n */\nexport function compareReceipt(\n expected: readonly ResolvedContextRow[],\n receipt: ContextReceipt,\n): { mismatches: ContextReceiptMismatch[]; systemRows: ContextReceiptRow[]; modelReadsContext: boolean } {\n const mismatches: ContextReceiptMismatch[] = [];\n // A turn whose model reads no context delivers nothing by design: every row\n // is `delivery: \"off\"`, `blocked_by: \"model\"`. That is not a lie about the\n // person's rules, so delivery is not compared; include / limit / rule still are.\n const modelReadsContext = receipt.model_reads_context !== false;\n const used = new Set<ContextReceiptRow>();\n const rows = receipt.rows ?? [];\n\n for (const exp of expected) {\n const actual =\n rows.find((r) => !used.has(r) && r.key === exp.key && r.surface_key === exp.surfaceKey) ??\n rows.find((r) => !used.has(r) && r.key === exp.key);\n if (!actual) {\n const withheldByOthers = !exp.include && exp.decided_by.include !== \"you\";\n if (!withheldByOthers) {\n mismatches.push({ key: exp.key, field: \"missing\", expected: exp.delivery, actual: null });\n }\n continue;\n }\n used.add(actual);\n if (actual.include !== exp.include) {\n mismatches.push({ key: exp.key, field: \"include\", expected: exp.include, actual: actual.include });\n }\n if (actual.max_inline_chars !== exp.max_inline_chars) {\n mismatches.push({\n key: exp.key,\n field: \"max_inline_chars\",\n expected: exp.max_inline_chars,\n actual: actual.max_inline_chars,\n });\n }\n if (\n modelReadsContext &&\n exp.chars !== null &&\n actual.chars !== null &&\n actual.delivery !== exp.delivery\n ) {\n mismatches.push({ key: exp.key, field: \"delivery\", expected: exp.delivery, actual: actual.delivery });\n }\n const expRule = normalizeUserRule(exp.userRule);\n const actRule = normalizeUserRule(actual.user_rule);\n if (!sameRule(expRule, actRule)) {\n mismatches.push({ key: exp.key, field: \"user_rule\", expected: expRule, actual: actRule });\n }\n }\n\n return { mismatches, systemRows: rows.filter((r) => !used.has(r)), modelReadsContext };\n}\n\n// ── receiptRowToResolved — read-only rows for a sent message ────────────────\n\n/**\n * Turn one receipt row into the row a read-only table renders (a sent\n * message's context, read back from `chat.message.model_context`). The value\n * itself is not in the receipt, so `value` is undefined.\n */\nexport function receiptRowToResolved(row: ContextReceiptRow): ResolvedContextRow {\n const origin: ContextRowOrigin =\n row.surface_key !== DEFAULT_SURFACE_KEY ? \"page\" : row.origin === \"client\" ? \"attached\" : \"system\";\n return {\n key: row.key,\n label: row.label,\n surfaceKey: row.surface_key,\n origin,\n value: undefined,\n chars: row.chars,\n userRule: normalizeUserRule(row.user_rule),\n include: row.include,\n max_inline_chars: row.max_inline_chars,\n delivery: row.delivery,\n decided_by: { include: row.decided_by.include, max_inline_chars: row.decided_by.max_inline_chars },\n clamped: row.clamped,\n };\n}\n\n// ── Display ─────────────────────────────────────────────────────────────────\n\n/** Compact size for a tabular column: `950`, `18.4k`, `184k`, `1.2M`, `—` for unknown. */\nexport function formatChars(n: number | null | undefined): string {\n if (n === null || n === undefined || !Number.isFinite(n)) return \"—\";\n const abs = Math.abs(n);\n const trim = (s: string) => s.replace(/\\.0$/, \"\");\n if (abs < 1000) return String(Math.round(n));\n if (abs < 100_000) return `${trim((n / 1000).toFixed(1))}k`;\n if (abs < 1_000_000) return `${Math.round(n / 1000)}k`;\n return `${trim((n / 1_000_000).toFixed(1))}M`;\n}\n","/**\n * Inlined Lucide shapes (C19 — no icon-library dependency): same 24×24 grid,\n * 2px stroke, `currentColor` only. Names match the Lucide originals.\n */\nimport type { ReactNode, SVGProps } from \"react\";\n\nexport type ContextIconProps = SVGProps<SVGSVGElement>;\n\nfunction icon(children: ReactNode) {\n return function Icon(props: ContextIconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n {...props}\n >\n {children}\n </svg>\n );\n };\n}\n\nexport const EyeIcon = icon(\n <>\n <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\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </>,\n);\nexport const EyeOffIcon = icon(\n <>\n <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\" />\n <path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\" />\n <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\" />\n <path d=\"m2 2 20 20\" />\n </>,\n);\nexport const RotateCcwIcon = icon(\n <>\n <path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\" />\n <path d=\"M3 3v5h5\" />\n </>,\n);\nexport const PanelRightIcon = icon(\n <>\n <rect width=\"18\" height=\"18\" x=\"3\" y=\"3\" rx=\"2\" />\n <path d=\"M15 3v18\" />\n </>,\n);\nexport const ChevronLeftIcon = icon(<path d=\"m15 18-6-6 6-6\" />);\nexport const TriangleAlertIcon = icon(\n <>\n <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\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </>,\n);\nexport const SearchIcon = icon(\n <>\n <circle cx=\"11\" cy=\"11\" r=\"8\" />\n <path d=\"m21 21-4.3-4.3\" />\n </>,\n);\n/** \"On request\" — the agent pulls the value down when it needs it. */\nexport const ArrowDownToLineIcon = icon(\n <>\n <path d=\"M12 17V3\" />\n <path d=\"m6 11 6 6 6-6\" />\n <path d=\"M19 21H5\" />\n </>,\n);\n","import * as React from \"react\";\nimport {\n Input,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n cn,\n} from \"@ai-matrx/design-system\";\n\nimport { RotateCcwIcon } from \"./icons\";\nimport { formatLimit } from \"./shared\";\n\nexport interface InlineMaxInputProps {\n /** The person's own limit, or null when inherited. */\n value: number | null;\n /** What applies without the person's number (shown muted). */\n inherited: number;\n cap: number;\n /** Next limit, or null to drop the person's number. */\n onCommit: (next: number | null) => void;\n disabled?: boolean | undefined;\n /** Accessible name — the row's label. */\n label: string;\n comfortable?: boolean;\n}\n\n/**\n * The Inline max cell: a 6ch numeric field. Inherited value shows as muted\n * placeholder text; an override shows a dot and a reset button. `0` reads\n * \"Never\". Commits on blur/Enter, Escape reverts, above-cap is clamped on\n * commit with a brief \"Limit is {cap}\" tooltip.\n */\nexport function InlineMaxInput({\n value,\n inherited,\n cap,\n onCommit,\n disabled,\n label,\n comfortable,\n}: InlineMaxInputProps) {\n const [focused, setFocused] = React.useState(false);\n const [draft, setDraft] = React.useState(\"\");\n const [notice, setNotice] = React.useState(false);\n const skip = React.useRef(false);\n\n React.useEffect(() => {\n if (!notice) return;\n const t = setTimeout(() => setNotice(false), 2000);\n return () => clearTimeout(t);\n }, [notice]);\n\n const commit = () => {\n const text = draft.trim();\n let next: number | null;\n if (text === \"\") next = null;\n else if (/^never$/i.test(text)) next = 0;\n else if (/^\\d+$/.test(text)) next = Number(text);\n else return;\n if (next !== null && next > cap) {\n next = cap;\n setNotice(true);\n }\n if (next !== value) onCommit(next);\n };\n\n const overridden = value !== null;\n\n return (\n <div className=\"flex items-center justify-end gap-1\">\n <span\n aria-hidden=\"true\"\n className={cn(\"h-1.5 w-1.5 shrink-0 rounded-full\", overridden ? \"bg-primary\" : \"bg-transparent\")}\n />\n <Tooltip open={notice}>\n <TooltipTrigger asChild>\n <Input\n type=\"text\"\n inputMode=\"numeric\"\n aria-label={`Inline max for ${label}`}\n disabled={disabled}\n value={focused ? draft : overridden ? formatLimit(value) : \"\"}\n placeholder={overridden ? undefined : formatLimit(inherited)}\n onFocus={() => {\n setDraft(overridden ? String(value) : \"\");\n setFocused(true);\n }}\n onChange={(e) => setDraft(e.target.value)}\n onBlur={() => {\n setFocused(false);\n if (skip.current) {\n skip.current = false;\n return;\n }\n commit();\n }}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") e.currentTarget.blur();\n else if (e.key === \"Escape\") {\n e.stopPropagation();\n skip.current = true;\n e.currentTarget.blur();\n }\n }}\n className={cn(\n \"w-[6.5ch] min-w-0 rounded px-1 py-0 text-right tabular-nums shadow-none\",\n comfortable ? \"h-8 text-base\" : \"h-6 text-xs\",\n )}\n />\n </TooltipTrigger>\n <TooltipContent>{`Limit is ${cap}`}</TooltipContent>\n </Tooltip>\n {overridden && !disabled ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={`Reset inline max for ${label}`}\n onClick={() => onCommit(null)}\n className={cn(\n \"inline-flex shrink-0 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground\",\n comfortable ? \"h-8 w-8\" : \"h-5 w-5\",\n )}\n >\n <RotateCcwIcon className=\"h-3 w-3\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>{`Reset to ${formatLimit(inherited)}`}</TooltipContent>\n </Tooltip>\n ) : (\n <span aria-hidden=\"true\" className={cn(\"shrink-0\", comfortable ? \"w-8\" : \"w-5\")} />\n )}\n </div>\n );\n}\n","import {\n resolveContextRule,\n type ContextDelivery,\n type ContextLayer,\n type ContextReceiptMismatch,\n type ResolvedContextRow,\n type SavedContextRule,\n} from \"../index\";\n\nexport const LAYER_LABEL: Record<ContextLayer, string> = {\n default: \"Default\",\n page: \"Page\",\n agent: \"Agent\",\n you: \"You\",\n};\n\nexport const DELIVERY_LABEL: Record<ContextDelivery, string> = {\n inline: \"Inline\",\n on_request: \"On request\",\n off: \"Off\",\n};\n\n/** `0` is \"Never\"; anything else is the number as typed. */\nexport function formatLimit(n: number): string {\n return n === 0 ? \"Never\" : String(n);\n}\n\n/** The limit this row would have without the person's own number. */\nexport function inheritedLimit(row: ResolvedContextRow, cap: number): number {\n return resolveContextRule({ ...(row.layers ?? {}), chars: row.chars, cap, user: null })\n .max_inline_chars;\n}\n\nexport function hasOverride(row: ResolvedContextRow): boolean {\n return row.userRule !== null && Object.keys(row.userRule).length > 0;\n}\n\nexport function withInclude(row: ResolvedContextRow, include: boolean): SavedContextRule {\n return { ...(row.userRule ?? {}), include };\n}\n\nexport function withLimit(row: ResolvedContextRow, limit: number | null): SavedContextRule | null {\n const next: SavedContextRule = { ...(row.userRule ?? {}) };\n if (limit === null) delete next.max_inline_chars;\n else next.max_inline_chars = limit;\n return Object.keys(next).length === 0 ? null : next;\n}\n\nexport function rowId(row: ResolvedContextRow): string {\n return `${row.surfaceKey}::${row.key}`;\n}\n\nfunction show(field: ContextReceiptMismatch[\"field\"], v: unknown): string {\n if (v === null || v === undefined) return \"none\";\n if (typeof v === \"boolean\") return v ? \"On\" : \"Off\";\n if (typeof v === \"number\") return formatLimit(v);\n if (field === \"delivery\" || field === \"missing\") {\n return DELIVERY_LABEL[v as ContextDelivery] ?? String(v);\n }\n if (typeof v === \"object\") {\n const r = v as SavedContextRule;\n const parts: string[] = [];\n if (r.include !== undefined) parts.push(r.include ? \"On\" : \"Off\");\n if (r.max_inline_chars !== undefined) parts.push(formatLimit(r.max_inline_chars));\n return parts.join(\", \") || \"none\";\n }\n return String(v);\n}\n\nconst FIELD_LABEL: Record<ContextReceiptMismatch[\"field\"], string> = {\n include: \"Include\",\n max_inline_chars: \"Inline max\",\n delivery: \"Delivery\",\n user_rule: \"Your rule\",\n missing: \"Not sent\",\n};\n\n/** One line per mismatch — \"Inline max: expected 8000, got 200\". Tooltip-sized. */\nexport function describeMismatches(list: readonly ContextReceiptMismatch[]): string {\n const text = list\n .map((m) =>\n m.field === \"missing\"\n ? \"Missing from the server's receipt\"\n : `${FIELD_LABEL[m.field]}: expected ${show(m.field, m.expected)}, got ${show(m.field, m.actual)}`,\n )\n .join(\" · \");\n return text.length > 140 ? `${text.slice(0, 139)}…` : text;\n}\n\n/** Tooltip for the \"on request\" marker, by why the value is not inline. */\nexport function onRequestReason(row: ResolvedContextRow): string {\n if (row.chars === null) return \"Size unknown — the agent reads it on request\";\n if (row.max_inline_chars === 0) return \"Never inline — the agent reads it on request\";\n return \"Over the limit — the agent reads it on request\";\n}\n","import * as React from \"react\";\nimport {\n BottomSheet,\n Popover,\n PopoverContent,\n PopoverTrigger,\n Switch,\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n cn,\n} from \"@ai-matrx/design-system\";\n\nimport {\n formatChars,\n type ContextReceiptMismatch,\n type ResolvedContextRow,\n type SavedContextRule,\n} from \"../index\";\nimport { ContextRulesTable } from \"./ContextRulesTable\";\nimport { EyeIcon, EyeOffIcon, PanelRightIcon, RotateCcwIcon, TriangleAlertIcon } from \"./icons\";\nimport { hasOverride } from \"./shared\";\n\nexport interface ContextRulesChipProps {\n /** The page's name — \"Notes\", \"Invoice 1042\". */\n label: string;\n rows: readonly ResolvedContextRow[];\n cap: number;\n /** Page context on/off. Omit when there is no page: the master switch is hidden. */\n on?: boolean | undefined;\n onToggleAll?: ((next: boolean) => void) | undefined;\n /** False: this turn's model cannot read context — muted face, no amber. */\n modelReadsContext?: boolean | undefined;\n onChange: (key: string, surfaceKey: string, next: SavedContextRule | null) => void;\n onResetAll: () => void;\n onOpenFullView: () => void;\n mismatchCount?: number;\n mismatches?: readonly ContextReceiptMismatch[];\n onOpenRow?: (key: string) => void;\n /** Bottom sheet instead of a popover. */\n isMobile?: boolean;\n readOnly?: boolean | undefined;\n open?: boolean;\n onOpenChange?: (open: boolean) => void;\n className?: string;\n}\n\nconst BLIND_TOOLTIP = \"This model can't read context\";\nconst BLIND_LABEL = \"Not read\";\n\nfunction summarize(rows: readonly ResolvedContextRow[]) {\n let count = 0;\n let chars = 0;\n for (const r of rows) {\n if (!r.include) continue;\n count += 1;\n chars += r.chars ?? 0;\n }\n return { count, chars };\n}\n\nfunction IconButton({\n label,\n onClick,\n comfortable,\n children,\n}: {\n label: string;\n onClick: () => void;\n comfortable: boolean;\n children: React.ReactNode;\n}) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n aria-label={label}\n onClick={onClick}\n className={cn(\n \"inline-flex shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground\",\n comfortable ? \"h-11 w-11\" : \"h-7 w-7\",\n )}\n >\n {children}\n </button>\n </TooltipTrigger>\n <TooltipContent>{label}</TooltipContent>\n </Tooltip>\n );\n}\n\n/**\n * The composer's context chip and the surface it opens: a header (label,\n * \"N · chars\" summary, page master switch, reset-all, full view) over the\n * compact rules table. Popover on desktop, bottom sheet on mobile.\n */\nexport function ContextRulesChip({\n label,\n rows,\n cap,\n on,\n onToggleAll,\n onChange,\n onResetAll,\n onOpenFullView,\n mismatchCount = 0,\n modelReadsContext = true,\n mismatches,\n onOpenRow,\n isMobile,\n readOnly,\n open: openProp,\n onOpenChange,\n className,\n}: ContextRulesChipProps) {\n const [openState, setOpenState] = React.useState(false);\n const open = openProp ?? openState;\n const setOpen = (next: boolean) => {\n if (openProp === undefined) setOpenState(next);\n onOpenChange?.(next);\n };\n const { count, chars } = summarize(rows);\n const anyOverride = rows.some(hasOverride);\n const blind = !modelReadsContext;\n const warn = mismatchCount > 0 && !blind;\n const comfortable = !!isMobile;\n const hasPage = on !== undefined;\n // Eye open only when context can reach the model: a page that is on (or no\n // page at all) and a model that reads context.\n const eyeOpen = !blind && on !== false;\n\n const faceButton = (\n <button\n type=\"button\"\n aria-label={`Context: ${label}`}\n data-mismatch={warn ? \"true\" : undefined}\n data-blind={blind ? \"true\" : undefined}\n onClick={isMobile ? () => setOpen(true) : undefined}\n className={cn(\n \"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\",\n !eyeOpen && \"text-muted-foreground\",\n blind && \"border-dashed\",\n warn && \"border-warning/60 ring-1 ring-warning\",\n className,\n )}\n >\n {eyeOpen ? <EyeIcon className=\"h-3.5 w-3.5 shrink-0\" /> : <EyeOffIcon className=\"h-3.5 w-3.5 shrink-0\" />}\n <span className=\"min-w-0 truncate\">{label}</span>\n <span className=\"shrink-0 tabular-nums text-muted-foreground\">{count}</span>\n {warn ? (\n <span className=\"inline-flex shrink-0 items-center gap-0.5 tabular-nums text-warning\">\n <TriangleAlertIcon className=\"h-3 w-3\" />\n {mismatchCount}\n </span>\n ) : null}\n </button>\n );\n\n // Tooltip on the face only for the blind state; the face's own label says the rest.\n const withBlindTip = (trigger: React.ReactElement) =>\n blind ? (\n <Tooltip>\n <TooltipTrigger asChild>{trigger}</TooltipTrigger>\n <TooltipContent>{BLIND_TOOLTIP}</TooltipContent>\n </Tooltip>\n ) : (\n trigger\n );\n\n const body = (\n <div className=\"flex min-h-0 flex-col\">\n <div\n className={cn(\n \"flex shrink-0 items-center gap-2 border-b border-border px-3\",\n comfortable ? \"h-12\" : \"h-10\",\n )}\n >\n {eyeOpen ? (\n <EyeIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n ) : (\n <EyeOffIcon className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n )}\n <span className=\"min-w-0 truncate text-sm font-medium\">{label}</span>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">\n {`${count} · ${formatChars(chars)} chars`}\n </span>\n <div className=\"ml-auto flex shrink-0 items-center gap-0.5\">\n {blind ? (\n <span className=\"mr-1 text-xs text-muted-foreground\">{BLIND_LABEL}</span>\n ) : null}\n {hasPage ? (\n <Switch\n size=\"sm\"\n aria-label=\"Page context\"\n checked={on}\n disabled={readOnly || !onToggleAll}\n onCheckedChange={(next) => onToggleAll?.(next)}\n className=\"mr-1\"\n />\n ) : null}\n {anyOverride && !readOnly ? (\n <IconButton label=\"Reset all\" onClick={onResetAll} comfortable={comfortable}>\n <RotateCcwIcon className=\"h-3.5 w-3.5\" />\n </IconButton>\n ) : null}\n <IconButton\n label=\"Open full view\"\n comfortable={comfortable}\n onClick={() => {\n setOpen(false);\n onOpenFullView();\n }}\n >\n <PanelRightIcon className=\"h-3.5 w-3.5\" />\n </IconButton>\n </div>\n </div>\n <div className={cn(\"min-h-0 overflow-y-auto\", comfortable ? \"max-h-[70dvh]\" : \"max-h-[min(24rem,60vh)]\")}>\n <ContextRulesTable\n rows={rows}\n cap={cap}\n readOnly={readOnly}\n density={comfortable ? \"comfortable\" : \"compact\"}\n onChange={onChange}\n {...(mismatches ? { mismatches } : {})}\n {...(onOpenRow ? { onOpenRow } : {})}\n />\n </div>\n </div>\n );\n\n if (isMobile) {\n return (\n <TooltipProvider delayDuration={300} titleTooltips={false}>\n {withBlindTip(faceButton)}\n <BottomSheet open={open} onOpenChange={setOpen} title={label} surface=\"solid\">\n {body}\n </BottomSheet>\n </TooltipProvider>\n );\n }\n\n return (\n <TooltipProvider delayDuration={300} titleTooltips={false}>\n <Popover open={open} onOpenChange={setOpen}>\n {withBlindTip(<PopoverTrigger asChild>{faceButton}</PopoverTrigger>)}\n <PopoverContent\n align=\"start\"\n className=\"w-[26rem] max-w-[calc(100vw-1rem)] overflow-hidden p-0\"\n >\n {body}\n </PopoverContent>\n </Popover>\n </TooltipProvider>\n );\n}\n","import * as React from \"react\";\nimport {\n Input,\n Switch,\n TooltipProvider,\n cn,\n} from \"@ai-matrx/design-system\";\n\nimport {\n DEFAULT_INLINE_MAX_CHARS,\n formatChars,\n type ContextLayer,\n type ContextReceiptMismatch,\n type ResolvedContextRow,\n type SavedContextRule,\n} from \"../index\";\nimport { ContextRulesTable } from \"./ContextRulesTable\";\nimport { ChevronLeftIcon, SearchIcon, TriangleAlertIcon } from \"./icons\";\nimport { InlineMaxInput } from \"./InlineMaxInput\";\nimport {\n DELIVERY_LABEL,\n LAYER_LABEL,\n describeMismatches,\n formatLimit,\n inheritedLimit,\n withInclude,\n withLimit,\n} from \"./shared\";\n\nexport interface ContextRulesPanelBodyProps {\n rows: readonly ResolvedContextRow[];\n cap: number;\n mismatches?: readonly ContextReceiptMismatch[];\n readOnly?: boolean | undefined;\n onChange: (key: string, surfaceKey: string, next: SavedContextRule | null) => void;\n /** Host content under the built-in controls (a value preview, source link…). */\n renderDetail?: (row: ResolvedContextRow) => React.ReactNode;\n isMobile?: boolean;\n /** Controlled selection; omit for internal state. */\n selectedKey?: string | null;\n onSelectedKeyChange?: (key: string | null) => void;\n className?: string;\n}\n\ninterface LayerCell {\n include: string;\n limit: string;\n}\n\n/** What each layer says about this row; \"—\" where the layer is silent. */\nfunction layerCells(row: ResolvedContextRow): Record<ContextLayer, LayerCell> {\n const { surface, agent, default_max } = row.layers ?? {};\n const declared = agent?.declared === true;\n const pageOff = surface?.declared === true && surface.auto_context === false;\n const num = (n: number | null | undefined) => (typeof n === \"number\" ? formatLimit(n) : \"—\");\n const rule = row.userRule;\n return {\n default: { include: \"On\", limit: formatLimit(default_max ?? DEFAULT_INLINE_MAX_CHARS) },\n page: { include: pageOff ? \"Off\" : \"—\", limit: num(surface?.max_inline_chars) },\n agent: {\n include: agent?.kill_switch && !declared ? \"Off\" : declared && pageOff ? \"On\" : \"—\",\n limit: declared ? num(agent?.max_inline_chars) : \"—\",\n },\n you: {\n include: rule?.include === undefined ? \"—\" : rule.include ? \"On\" : \"Off\",\n limit: num(rule?.max_inline_chars),\n },\n };\n}\n\nconst LAYERS: ContextLayer[] = [\"default\", \"page\", \"agent\", \"you\"];\n\nfunction LayerTable({ row }: { row: ResolvedContextRow }) {\n const cells = layerCells(row);\n const cell = (text: string, winning: boolean) => (\n <span\n role=\"cell\"\n data-winning={winning ? \"true\" : undefined}\n className={cn(\n \"rounded px-1.5 py-0.5 text-right tabular-nums\",\n winning ? \"bg-primary/10 font-medium text-foreground\" : \"text-muted-foreground\",\n )}\n >\n {text}\n </span>\n );\n return (\n <div role=\"table\" aria-label=\"Layers\" className=\"text-xs\">\n <div\n role=\"row\"\n className=\"grid h-7 grid-cols-[1fr_5rem_5rem] items-center gap-x-2 border-b border-border font-medium text-muted-foreground\"\n >\n <span role=\"columnheader\">Layer</span>\n <span role=\"columnheader\" className=\"text-right\">\n Include\n </span>\n <span role=\"columnheader\" className=\"text-right\">\n Inline max\n </span>\n </div>\n {LAYERS.map((layer) => (\n <div\n role=\"row\"\n key={layer}\n className=\"grid h-7 grid-cols-[1fr_5rem_5rem] items-center gap-x-2 border-b border-border/50\"\n >\n <span role=\"cell\">{LAYER_LABEL[layer]}</span>\n {cell(cells[layer].include, row.decided_by.include === layer)}\n {cell(cells[layer].limit, row.decided_by.max_inline_chars === layer)}\n </div>\n ))}\n </div>\n );\n}\n\nfunction RowDetail({\n row,\n cap,\n readOnly,\n mismatches,\n onChange,\n renderDetail,\n comfortable,\n}: {\n row: ResolvedContextRow;\n cap: number;\n readOnly: boolean | undefined;\n mismatches: ContextReceiptMismatch[];\n onChange: ContextRulesPanelBodyProps[\"onChange\"];\n renderDetail: ContextRulesPanelBodyProps[\"renderDetail\"];\n comfortable: boolean;\n}) {\n return (\n <div className=\"flex flex-col gap-3 p-3\">\n <div className=\"flex min-w-0 items-baseline gap-2\">\n <h3 className=\"min-w-0 truncate text-sm font-medium\">{row.label}</h3>\n <span className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">\n {`${formatChars(row.chars)} chars · ${DELIVERY_LABEL[row.delivery]}`}\n </span>\n </div>\n {mismatches.length > 0 ? (\n <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\">\n <TriangleAlertIcon className=\"mt-0.5 h-3.5 w-3.5 shrink-0\" />\n <span>{describeMismatches(mismatches)}</span>\n </div>\n ) : null}\n <div className=\"grid grid-cols-[auto_1fr] items-center gap-x-4 gap-y-2 text-xs\">\n <span className=\"text-muted-foreground\">Include</span>\n <div className={cn(\"flex items-center\", comfortable ? \"h-11\" : \"h-7\")}>\n <Switch\n size=\"sm\"\n aria-label={`Include ${row.label}`}\n checked={row.include}\n disabled={readOnly}\n onCheckedChange={(next) => onChange(row.key, row.surfaceKey, withInclude(row, next))}\n />\n </div>\n <span className=\"text-muted-foreground\">Inline max</span>\n <div className=\"flex\">\n <InlineMaxInput\n label={row.label}\n value={row.userRule?.max_inline_chars ?? null}\n inherited={inheritedLimit(row, cap)}\n cap={cap}\n disabled={readOnly}\n comfortable={comfortable}\n onCommit={(next) => onChange(row.key, row.surfaceKey, withLimit(row, next))}\n />\n </div>\n </div>\n <LayerTable row={row} />\n {renderDetail ? renderDetail(row) : null}\n </div>\n );\n}\n\n/**\n * Master/detail body for a docked context panel: search + compact table on\n * the left, the open row's controls, layer breakdown and host detail on the\n * right. On mobile: list, then detail with Back.\n */\nexport function ContextRulesPanelBody({\n rows,\n cap,\n mismatches,\n readOnly,\n onChange,\n renderDetail,\n isMobile,\n selectedKey: selectedProp,\n onSelectedKeyChange,\n className,\n}: ContextRulesPanelBodyProps) {\n const [selectedState, setSelectedState] = React.useState<string | null>(null);\n const [query, setQuery] = React.useState(\"\");\n const selectedKey = selectedProp !== undefined ? selectedProp : selectedState;\n const select = (key: string | null) => {\n if (selectedProp === undefined) setSelectedState(key);\n onSelectedKeyChange?.(key);\n };\n\n const q = query.trim().toLowerCase();\n const visible = q\n ? rows.filter((r) => r.label.toLowerCase().includes(q) || r.key.toLowerCase().includes(q))\n : rows;\n const selected = selectedKey ? rows.find((r) => r.key === selectedKey) ?? null : null;\n const comfortable = !!isMobile;\n\n const search = (\n <div className=\"relative shrink-0 border-b border-border p-2\">\n <SearchIcon className=\"pointer-events-none absolute left-4 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground\" />\n <Input\n type=\"search\"\n aria-label=\"Search context\"\n placeholder=\"Search\"\n value={query}\n onChange={(e) => setQuery(e.target.value)}\n className={cn(\"pl-7 shadow-none\", comfortable ? \"h-11 text-base\" : \"h-8 text-xs\")}\n />\n </div>\n );\n\n const table = (\n <div className=\"min-h-0 flex-1 overflow-y-auto\">\n <ContextRulesTable\n rows={visible}\n cap={cap}\n readOnly={readOnly}\n density={comfortable ? \"comfortable\" : \"compact\"}\n selectedKey={selectedKey}\n onChange={onChange}\n onOpenRow={(key) => select(key)}\n {...(mismatches ? { mismatches } : {})}\n />\n </div>\n );\n\n const detail = selected ? (\n <RowDetail\n row={selected}\n cap={cap}\n readOnly={readOnly}\n mismatches={mismatches?.filter((m) => m.key === selected.key) ?? []}\n onChange={onChange}\n renderDetail={renderDetail}\n comfortable={comfortable}\n />\n ) : null;\n\n if (isMobile) {\n return (\n <TooltipProvider delayDuration={300} titleTooltips={false}>\n <div className={cn(\"flex h-full min-h-0 flex-col\", className)}>\n {selected ? (\n <>\n <div className=\"flex h-12 shrink-0 items-center border-b border-border px-1\">\n <button\n type=\"button\"\n onClick={() => select(null)}\n className=\"inline-flex h-11 items-center gap-1 rounded-md px-2 text-sm text-muted-foreground hover:text-foreground\"\n >\n <ChevronLeftIcon className=\"h-4 w-4\" />\n Back\n </button>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto\">{detail}</div>\n </>\n ) : (\n <>\n {search}\n {table}\n </>\n )}\n </div>\n </TooltipProvider>\n );\n }\n\n return (\n <TooltipProvider delayDuration={300} titleTooltips={false}>\n <div className={cn(\"flex h-full min-h-0\", className)}>\n <aside className=\"flex w-[22rem] shrink-0 flex-col border-r border-border\">\n {search}\n {table}\n </aside>\n <section className=\"min-h-0 min-w-0 flex-1 overflow-y-auto\">\n {detail ?? (\n <div className=\"flex h-full items-center justify-center text-xs text-muted-foreground\">\n Select an item\n </div>\n )}\n </section>\n </div>\n </TooltipProvider>\n );\n}\n"],"mappings":"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","names":["import_design_system","import_jsx_runtime","import_jsx_runtime","React","import_design_system","import_jsx_runtime","React","import_design_system","import_jsx_runtime"]}
|
|
@@ -96,9 +96,11 @@ interface ContextRulesChipProps {
|
|
|
96
96
|
label: string;
|
|
97
97
|
rows: readonly ResolvedContextRow[];
|
|
98
98
|
cap: number;
|
|
99
|
-
/** Page context on/off. */
|
|
100
|
-
on
|
|
101
|
-
onToggleAll
|
|
99
|
+
/** Page context on/off. Omit when there is no page: the master switch is hidden. */
|
|
100
|
+
on?: boolean | undefined;
|
|
101
|
+
onToggleAll?: ((next: boolean) => void) | undefined;
|
|
102
|
+
/** False: this turn's model cannot read context — muted face, no amber. */
|
|
103
|
+
modelReadsContext?: boolean | undefined;
|
|
102
104
|
onChange: (key: string, surfaceKey: string, next: SavedContextRule | null) => void;
|
|
103
105
|
onResetAll: () => void;
|
|
104
106
|
onOpenFullView: () => void;
|
|
@@ -117,7 +119,7 @@ interface ContextRulesChipProps {
|
|
|
117
119
|
* "N · chars" summary, page master switch, reset-all, full view) over the
|
|
118
120
|
* compact rules table. Popover on desktop, bottom sheet on mobile.
|
|
119
121
|
*/
|
|
120
|
-
declare function ContextRulesChip({ label, rows, cap, on, onToggleAll, onChange, onResetAll, onOpenFullView, mismatchCount, mismatches, onOpenRow, isMobile, readOnly, open: openProp, onOpenChange, className, }: ContextRulesChipProps): react.JSX.Element;
|
|
122
|
+
declare function ContextRulesChip({ label, rows, cap, on, onToggleAll, onChange, onResetAll, onOpenFullView, mismatchCount, modelReadsContext, mismatches, onOpenRow, isMobile, readOnly, open: openProp, onOpenChange, className, }: ContextRulesChipProps): react.JSX.Element;
|
|
121
123
|
|
|
122
124
|
interface ContextRulesPanelBodyProps {
|
|
123
125
|
rows: readonly ResolvedContextRow[];
|
|
@@ -96,9 +96,11 @@ interface ContextRulesChipProps {
|
|
|
96
96
|
label: string;
|
|
97
97
|
rows: readonly ResolvedContextRow[];
|
|
98
98
|
cap: number;
|
|
99
|
-
/** Page context on/off. */
|
|
100
|
-
on
|
|
101
|
-
onToggleAll
|
|
99
|
+
/** Page context on/off. Omit when there is no page: the master switch is hidden. */
|
|
100
|
+
on?: boolean | undefined;
|
|
101
|
+
onToggleAll?: ((next: boolean) => void) | undefined;
|
|
102
|
+
/** False: this turn's model cannot read context — muted face, no amber. */
|
|
103
|
+
modelReadsContext?: boolean | undefined;
|
|
102
104
|
onChange: (key: string, surfaceKey: string, next: SavedContextRule | null) => void;
|
|
103
105
|
onResetAll: () => void;
|
|
104
106
|
onOpenFullView: () => void;
|
|
@@ -117,7 +119,7 @@ interface ContextRulesChipProps {
|
|
|
117
119
|
* "N · chars" summary, page master switch, reset-all, full view) over the
|
|
118
120
|
* compact rules table. Popover on desktop, bottom sheet on mobile.
|
|
119
121
|
*/
|
|
120
|
-
declare function ContextRulesChip({ label, rows, cap, on, onToggleAll, onChange, onResetAll, onOpenFullView, mismatchCount, mismatches, onOpenRow, isMobile, readOnly, open: openProp, onOpenChange, className, }: ContextRulesChipProps): react.JSX.Element;
|
|
122
|
+
declare function ContextRulesChip({ label, rows, cap, on, onToggleAll, onChange, onResetAll, onOpenFullView, mismatchCount, modelReadsContext, mismatches, onOpenRow, isMobile, readOnly, open: openProp, onOpenChange, className, }: ContextRulesChipProps): react.JSX.Element;
|
|
121
123
|
|
|
122
124
|
interface ContextRulesPanelBodyProps {
|
|
123
125
|
rows: readonly ResolvedContextRow[];
|
|
@@ -515,6 +515,8 @@ import {
|
|
|
515
515
|
cn as cn3
|
|
516
516
|
} from "@ai-matrx/design-system";
|
|
517
517
|
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
518
|
+
var BLIND_TOOLTIP = "This model can't read context";
|
|
519
|
+
var BLIND_LABEL = "Not read";
|
|
518
520
|
function summarize(rows) {
|
|
519
521
|
let count = 0;
|
|
520
522
|
let chars = 0;
|
|
@@ -558,6 +560,7 @@ function ContextRulesChip({
|
|
|
558
560
|
onResetAll,
|
|
559
561
|
onOpenFullView,
|
|
560
562
|
mismatchCount = 0,
|
|
563
|
+
modelReadsContext = true,
|
|
561
564
|
mismatches,
|
|
562
565
|
onOpenRow,
|
|
563
566
|
isMobile,
|
|
@@ -574,23 +577,28 @@ function ContextRulesChip({
|
|
|
574
577
|
};
|
|
575
578
|
const { count, chars } = summarize(rows);
|
|
576
579
|
const anyOverride = rows.some(hasOverride);
|
|
577
|
-
const
|
|
580
|
+
const blind = !modelReadsContext;
|
|
581
|
+
const warn = mismatchCount > 0 && !blind;
|
|
578
582
|
const comfortable = !!isMobile;
|
|
579
|
-
const
|
|
583
|
+
const hasPage = on !== void 0;
|
|
584
|
+
const eyeOpen = !blind && on !== false;
|
|
585
|
+
const faceButton = /* @__PURE__ */ jsxs4(
|
|
580
586
|
"button",
|
|
581
587
|
{
|
|
582
588
|
type: "button",
|
|
583
589
|
"aria-label": `Context: ${label}`,
|
|
584
590
|
"data-mismatch": warn ? "true" : void 0,
|
|
591
|
+
"data-blind": blind ? "true" : void 0,
|
|
585
592
|
onClick: isMobile ? () => setOpen(true) : void 0,
|
|
586
593
|
className: cn3(
|
|
587
594
|
"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
|
-
!
|
|
595
|
+
!eyeOpen && "text-muted-foreground",
|
|
596
|
+
blind && "border-dashed",
|
|
589
597
|
warn && "border-warning/60 ring-1 ring-warning",
|
|
590
598
|
className
|
|
591
599
|
),
|
|
592
600
|
children: [
|
|
593
|
-
|
|
601
|
+
eyeOpen ? /* @__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
602
|
/* @__PURE__ */ jsx4("span", { className: "min-w-0 truncate", children: label }),
|
|
595
603
|
/* @__PURE__ */ jsx4("span", { className: "shrink-0 tabular-nums text-muted-foreground", children: count }),
|
|
596
604
|
warn ? /* @__PURE__ */ jsxs4("span", { className: "inline-flex shrink-0 items-center gap-0.5 tabular-nums text-warning", children: [
|
|
@@ -600,6 +608,10 @@ function ContextRulesChip({
|
|
|
600
608
|
]
|
|
601
609
|
}
|
|
602
610
|
);
|
|
611
|
+
const withBlindTip = (trigger) => blind ? /* @__PURE__ */ jsxs4(Tooltip3, { children: [
|
|
612
|
+
/* @__PURE__ */ jsx4(TooltipTrigger3, { asChild: true, children: trigger }),
|
|
613
|
+
/* @__PURE__ */ jsx4(TooltipContent3, { children: BLIND_TOOLTIP })
|
|
614
|
+
] }) : trigger;
|
|
603
615
|
const body = /* @__PURE__ */ jsxs4("div", { className: "flex min-h-0 flex-col", children: [
|
|
604
616
|
/* @__PURE__ */ jsxs4(
|
|
605
617
|
"div",
|
|
@@ -609,21 +621,22 @@ function ContextRulesChip({
|
|
|
609
621
|
comfortable ? "h-12" : "h-10"
|
|
610
622
|
),
|
|
611
623
|
children: [
|
|
612
|
-
|
|
624
|
+
eyeOpen ? /* @__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
625
|
/* @__PURE__ */ jsx4("span", { className: "min-w-0 truncate text-sm font-medium", children: label }),
|
|
614
626
|
/* @__PURE__ */ jsx4("span", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", children: `${count} \xB7 ${formatChars(chars)} chars` }),
|
|
615
627
|
/* @__PURE__ */ jsxs4("div", { className: "ml-auto flex shrink-0 items-center gap-0.5", children: [
|
|
616
|
-
/* @__PURE__ */ jsx4(
|
|
628
|
+
blind ? /* @__PURE__ */ jsx4("span", { className: "mr-1 text-xs text-muted-foreground", children: BLIND_LABEL }) : null,
|
|
629
|
+
hasPage ? /* @__PURE__ */ jsx4(
|
|
617
630
|
Switch2,
|
|
618
631
|
{
|
|
619
632
|
size: "sm",
|
|
620
633
|
"aria-label": "Page context",
|
|
621
634
|
checked: on,
|
|
622
|
-
disabled: readOnly,
|
|
623
|
-
onCheckedChange: onToggleAll,
|
|
635
|
+
disabled: readOnly || !onToggleAll,
|
|
636
|
+
onCheckedChange: (next) => onToggleAll?.(next),
|
|
624
637
|
className: "mr-1"
|
|
625
638
|
}
|
|
626
|
-
),
|
|
639
|
+
) : null,
|
|
627
640
|
anyOverride && !readOnly ? /* @__PURE__ */ jsx4(IconButton, { label: "Reset all", onClick: onResetAll, comfortable, children: /* @__PURE__ */ jsx4(RotateCcwIcon, { className: "h-3.5 w-3.5" }) }) : null,
|
|
628
641
|
/* @__PURE__ */ jsx4(
|
|
629
642
|
IconButton,
|
|
@@ -656,12 +669,12 @@ function ContextRulesChip({
|
|
|
656
669
|
] });
|
|
657
670
|
if (isMobile) {
|
|
658
671
|
return /* @__PURE__ */ jsxs4(TooltipProvider2, { delayDuration: 300, titleTooltips: false, children: [
|
|
659
|
-
|
|
672
|
+
withBlindTip(faceButton),
|
|
660
673
|
/* @__PURE__ */ jsx4(BottomSheet, { open, onOpenChange: setOpen, title: label, surface: "solid", children: body })
|
|
661
674
|
] });
|
|
662
675
|
}
|
|
663
676
|
return /* @__PURE__ */ jsx4(TooltipProvider2, { delayDuration: 300, titleTooltips: false, children: /* @__PURE__ */ jsxs4(Popover, { open, onOpenChange: setOpen, children: [
|
|
664
|
-
/* @__PURE__ */ jsx4(PopoverTrigger, { asChild: true, children:
|
|
677
|
+
withBlindTip(/* @__PURE__ */ jsx4(PopoverTrigger, { asChild: true, children: faceButton })),
|
|
665
678
|
/* @__PURE__ */ jsx4(
|
|
666
679
|
PopoverContent,
|
|
667
680
|
{
|