candidates and board ui agent issue
Some checks failed
CI / check (push) Failing after 4m58s

This commit is contained in:
2026-09-05 10:46:06 +05:30
parent e02a0c23d4
commit 6249e00a3a
78 changed files with 15071 additions and 1998 deletions

View File

@@ -394,6 +394,10 @@ export function AgentSkillWorkspace({
busy={busy}
query={boardQuery}
onQueryChange={setBoardQuery}
/* Ownership, through the one handler that writes `agent.skills` —
the same one the Owliver catalog attaches with. */
attachedIds={attachedIds}
onAttach={onToggleSkill}
/>
)}
</div>

View File

@@ -1,5 +1,5 @@
import * as React from 'react';
import { LayoutTemplate, Pencil, Plus, SearchX } from 'lucide-react';
import { LayoutTemplate, Minus, Pencil, Plus, SearchX } from 'lucide-react';
import { Link } from 'react-router-dom';
import { cn } from '@/lib/utils';
import { Alert, Button, SearchInput, Switch } from '@/components/ds';
@@ -9,24 +9,30 @@ import { Alert, Button, SearchInput, Switch } from '@/components/ds';
*
* The second half of one Skills section — the same heading, a tab away from the
* Owliver catalog — so nobody has to decide between two top-level destinations
* ever again. What it is *not* is a second copy of that catalog with the word
* Board on it, and the reason is worth stating because it is the one thing here
* that could quietly become a lie:
* ever again.
*
* **A Board skill is not carried by an agent.** `SkillSurface` renders a
* section from the page it names and the account's `disabledSkills`; it does not
* read `agent.skills` and has no agent in scope. Writing a Board skill id into
* `agent.skills` would therefore record an assignment nothing honours — a card
* that says "Added" and a product that behaves identically either way.
* **Two controls, because there are two different questions.** This card used to
* offer only the workspace switch, and said so at length: a Board skill was not
* carried by an agent, because `SkillSurface` read the page and the account's
* `disabledSkills` and never looked at `agent.skills`. That was true, and it is
* not any more — `useSkillSections` now asks `agentPermitsSkill`, so an id
* written into `agent.skills` is honoured on the page.
*
* So the relationship shown is the real one: these are the sections the pages
* *this agent answers on* will draw, and the control offered is the one that
* actually governs them — the workspace switch every surface already reads. It
* is labelled as workspace-wide, because it is.
* So both questions are asked here, and neither is dressed up as the other:
*
* - **Active** is the workspace switch. Off means off for everyone, on every
* page, for every agent. It is the account's `disabledSkills`.
* - **Add to agent** is ownership. It writes this skill's id into
* `agent.skills`, through the same handler the Owliver catalog uses.
*
* Ownership is opt-in and that is what makes the two safe together: a skill no
* agent claims still draws wherever its `pages:` say, exactly as before. The
* first agent to claim it is what narrows it — which is why attaching is worth
* saying out loud on the card rather than leaving as a silent side effect.
*/
/** One Board skill: what it draws, where, and whether it is switched on. */
function BoardCard({ entry, enabled, onToggle, onSurfaces, busy }) {
function BoardCard({ entry, enabled, onToggle, onSurfaces, busy, attached = false, onAttach = null }) {
const switchId = `board-${entry.id}`;
return (
@@ -110,6 +116,31 @@ function BoardCard({ entry, enabled, onToggle, onSurfaces, busy }) {
)}
</div>
{/* Ownership, separate from the workspace switch above it. The button
writes `agent.skills` through the same handler the Owliver catalog
uses — there is no second assignment path and nothing new stored. */}
{onAttach && (
<div className="relative z-10 mt-3 flex items-center justify-between gap-2 rounded-lg border border-border/60 bg-surface-subtle px-2.5 py-2">
<span className="min-w-0 text-caption text-ink-3">
{attached
? 'Owned by this agent'
: 'Not owned by any agent on this page'}
</span>
<Button
size="xs"
variant={attached ? 'outline' : 'default'}
shape="rounded"
disabled={busy}
onClick={() => onAttach(entry.id)}
aria-label={`${attached ? 'Remove' : 'Add'} ${entry.name} ${attached ? 'from' : 'to'} this agent`}
>
{attached
? <><Minus className="mr-1 h-3.5 w-3.5" aria-hidden="true" />Remove</>
: <><Plus className="mr-1 h-3.5 w-3.5" aria-hidden="true" />Add to agent</>}
</Button>
</div>
)}
<div className="relative z-10 mt-4 flex items-center justify-between gap-2 border-t border-border/60 pt-3 font-medium">
<span className="text-caption text-ink-4">
{entry.surfaces.some((s) => onSurfaces.has(s.id))
@@ -131,6 +162,7 @@ function BoardCard({ entry, enabled, onToggle, onSurfaces, busy }) {
/** @param {any} props */
export function BoardSkillList({
entries, agentPages = [], disabledIds, onToggle, busy = false, query, onQueryChange, total,
attachedIds = null, onAttach = null,
}) {
const searchId = React.useId();
const onSurfaces = React.useMemo(() => new Set(agentPages), [agentPages]);
@@ -147,9 +179,11 @@ export function BoardSkillList({
return (
<section aria-label="Board skills" className="flex min-w-0 flex-col gap-4">
<Alert tone="info" title="Board skills belong to a page, not to an agent">
They draw sections on KROW pages and are switched on for the whole workspace —
so a change here affects every agent answering on that page, not just this one.
<Alert tone="info" title="Two switches, two different questions">
<strong>Active</strong> is workspace-wide: off means off on every page, for every
agent. <strong>Add to agent</strong> is ownership — once any agent owns a board
skill, it draws only where an owning agent is answering. A skill no agent owns
keeps drawing wherever its pages say, as before.
</Alert>
{total > 0 && (
@@ -192,6 +226,8 @@ export function BoardSkillList({
onToggle={onToggle}
onSurfaces={onSurfaces}
busy={busy}
attached={Boolean(attachedIds?.has(entry.id))}
onAttach={onAttach}
/>
))}
</ul>