import * as React from 'react'; import { AlertCircle, BookOpen, CheckCircle2, Cpu, Layers, Play, Search, Sparkles, Wrench, } from 'lucide-react'; import { Badge, Input, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ds'; import { allSkills, matchSkill, pageKeyForContext, skillsForContext } from '@/lib/skills/registry'; import { PLACEMENT_ROUTES } from '@/components/ai-assistant/placement'; import { ASSISTANT_CONTEXTS } from '@/components/ai-assistant/contexts'; import { agentCovers, agentScopedDisabled, classifyQuestion } from '@/lib/agents/runtime'; import { toolsForContext } from '@/lib/skills/tools'; import { retrieveKnowledge } from '@/lib/agents/knowledge'; import { cn } from '@/lib/utils'; /** * What this agent would do, on a page, before it is published. * * Runs the live runtime classifier, skill matcher, tool resolver, and * knowledge retriever to display comprehensive diagnostics. */ const CONTEXT_OPTIONS = Object.entries(PLACEMENT_ROUTES).map(([route, contextId]) => ({ contextId, route, label: ASSISTANT_CONTEXTS[contextId]?.page || contextId, })); const CLASSIFICATION_COPY = { structured: 'Reads workforce records through an attached skill.', knowledge: 'Answers directly from reference knowledge.', combined: 'Requires both structured records and knowledge retrieval.', }; /** @param {any} props */ export function AgentTestPanel({ fields, dirty, customSkills = [], onRunLive }) { const [contextId, setContextId] = React.useState( () => CONTEXT_OPTIONS.find((o) => fields.pages.includes(pageKeyForContext(o.contextId)))?.contextId || CONTEXT_OPTIONS[0].contextId ); const [question, setQuestion] = React.useState('What needs my attention?'); /* The draft as the runtime sees it */ const draftAgent = React.useMemo(() => ({ id: fields.id || 'draft', name: fields.name || 'This agent', pages: fields.pages, skills: fields.skills, subagents: fields.subagents, knowledge: fields.knowledge, starters: fields.starters, reasoning: fields.reasoning, webSearch: fields.webSearch, status: 'published', }), [fields]); const registry = React.useMemo(() => allSkills(customSkills), [customSkills]); const result = React.useMemo(() => { const covers = agentCovers(draftAgent, contextId); const disabled = agentScopedDisabled(draftAgent, registry, []); const pageOnly = skillsForContext(contextId, [], customSkills); const scoped = covers ? skillsForContext(contextId, disabled, customSkills) : []; const matched = covers ? matchSkill(question, contextId, disabled, customSkills) : null; return { covers, disabled, pageOnly, scoped, matched, tools: covers ? toolsForContext(contextId, disabled, customSkills) : [], knowledge: retrieveKnowledge({ agent: draftAgent, contextId, question }), classification: classifyQuestion({ question }), }; }, [draftAgent, contextId, question, registry, customSkills]); const activePageLabel = ASSISTANT_CONTEXTS[contextId]?.page || 'Current Page'; return (
{/* ── Test Workbench Card ────────────────────────────────────────── */}

Simulation & Scope Diagnostics

Evaluate real-time intent routing and skill activation without publishing changes.

{dirty && ( Testing unsaved draft )}
setQuestion(e.target.value)} placeholder="e.g. Which roles are at risk?" className="pl-9 w-full bg-surface" />
{/* Everything else on this tab is a STATIC read of where a question would route. Useful, and not the same as asking. The tab is called Test, so a reader reasonably expects to be able to run the thing — this is that, through the existing Owliver panel and the draft's own scope, so the answer comes from the agent being edited rather than the published one. */} {onRunLive && ( )}
{fields.starters.filter((s) => s.label).length > 0 && (
Suggested Starters: {fields.starters.filter((s) => s.label).map((s, i) => ( ))}
)}
{/* ── Active Status Banner ───────────────────────────────────────── */}
{result.covers ? : }

{result.covers ? `Active on ${activePageLabel}` : `Constrained on ${activePageLabel}`}

{result.covers ? result.scoped.length ? `${result.scoped.length} of ${result.pageOnly.length} operational skills are active and ready on this surface.` : `This page provides ${result.pageOnly.length} skills. With none attached, this agent will answer using the page's standard reader.` : `This agent has not been assigned to ${activePageLabel}. When asked on this page, it will politely decline or defer to the workspace reader.`}

{/* ── 4-Quadrant Diagnostic Grid ─────────────────────────────────── */}
{/* Quadrant 1: Intent & Skill Routing */}

Intent & Skill Routing

{CLASSIFICATION_COPY[result.classification] || CLASSIFICATION_COPY.structured}

{result.matched ? (
{result.matched.name} Matched

{result.matched.description}

) : (
No specialized skill claimed this exact wording. The native page reader will process the query.
)}
{/* Quadrant 2: Reachable Skills */}

Reachable Page Skills

{result.scoped.length}
{result.scoped.length ? (
{result.scoped.map((s) => (
{s.name} Ready
))}
) : (
No attached skills apply to {activePageLabel}.
)}
{/* Quadrant 3: Execution Capabilities */}

Execution Actions & Tools

{result.tools.length}
{result.tools.length ? (
{result.tools.map((tool) => (
{tool.label} {tool.requiresApproval ? ( Confirmation required ) : ( Read-only )}
))}
) : (
Read-only operations. No active mutations or system write actions.
)}
{/* Quadrant 4: Referenced Knowledge */}

Referenced Knowledge

{result.knowledge.passages.length ? (
{result.knowledge.passages.map((p) => (
{p.label} {p.text}
))}
) : (
{result.knowledge.note || 'No custom reference knowledge attached to this agent.'}
)}
); } export default AgentTestPanel;