Files
paperclip/ui/src/components/AgentProperties.tsx
Forgotten b0f3f04ac6 feat: add OpenClaw adapter type
Introduce openclaw adapter package with server execution, CLI stream
formatting, and UI config fields. Register the adapter across CLI,
server, and UI registries. Add adapter label in all relevant pages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 16:32:59 -06:00

102 lines
3.5 KiB
TypeScript

import { useQuery } from "@tanstack/react-query";
import { Link } from "react-router-dom";
import type { Agent, AgentRuntimeState } from "@paperclip/shared";
import { agentsApi } from "../api/agents";
import { useCompany } from "../context/CompanyContext";
import { queryKeys } from "../lib/queryKeys";
import { StatusBadge } from "./StatusBadge";
import { Identity } from "./Identity";
import { formatDate } from "../lib/utils";
import { Separator } from "@/components/ui/separator";
interface AgentPropertiesProps {
agent: Agent;
runtimeState?: AgentRuntimeState;
}
const adapterLabels: Record<string, string> = {
claude_local: "Claude (local)",
codex_local: "Codex (local)",
openclaw: "OpenClaw",
process: "Process",
http: "HTTP",
};
function PropertyRow({ label, children }: { label: string; children: React.ReactNode }) {
return (
<div className="flex items-center gap-3 py-1.5">
<span className="text-xs text-muted-foreground shrink-0 w-20">{label}</span>
<div className="flex items-center gap-1.5 min-w-0">{children}</div>
</div>
);
}
export function AgentProperties({ agent, runtimeState }: AgentPropertiesProps) {
const { selectedCompanyId } = useCompany();
const { data: agents } = useQuery({
queryKey: queryKeys.agents.list(selectedCompanyId!),
queryFn: () => agentsApi.list(selectedCompanyId!),
enabled: !!selectedCompanyId && !!agent.reportsTo,
});
const reportsToAgent = agent.reportsTo ? agents?.find((a) => a.id === agent.reportsTo) : null;
return (
<div className="space-y-4">
<div className="space-y-1">
<PropertyRow label="Status">
<StatusBadge status={agent.status} />
</PropertyRow>
<PropertyRow label="Role">
<span className="text-sm">{agent.role}</span>
</PropertyRow>
{agent.title && (
<PropertyRow label="Title">
<span className="text-sm">{agent.title}</span>
</PropertyRow>
)}
<PropertyRow label="Adapter">
<span className="text-sm font-mono">{adapterLabels[agent.adapterType] ?? agent.adapterType}</span>
</PropertyRow>
</div>
<Separator />
<div className="space-y-1">
{(runtimeState?.sessionDisplayId ?? runtimeState?.sessionId) && (
<PropertyRow label="Session">
<span className="text-xs font-mono">
{String(runtimeState.sessionDisplayId ?? runtimeState.sessionId).slice(0, 12)}...
</span>
</PropertyRow>
)}
{runtimeState?.lastError && (
<PropertyRow label="Last error">
<span className="text-xs text-red-600 dark:text-red-400 truncate max-w-[160px]">{runtimeState.lastError}</span>
</PropertyRow>
)}
{agent.lastHeartbeatAt && (
<PropertyRow label="Last Heartbeat">
<span className="text-sm">{formatDate(agent.lastHeartbeatAt)}</span>
</PropertyRow>
)}
{agent.reportsTo && (
<PropertyRow label="Reports To">
{reportsToAgent ? (
<Link to={`/agents/${reportsToAgent.id}`} className="hover:underline">
<Identity name={reportsToAgent.name} size="sm" />
</Link>
) : (
<span className="text-sm font-mono">{agent.reportsTo.slice(0, 8)}</span>
)}
</PropertyRow>
)}
<PropertyRow label="Created">
<span className="text-sm">{formatDate(agent.createdAt)}</span>
</PropertyRow>
</div>
</div>
);
}