/**
* Composer "+" > Capabilities: what the agent can do in this chat. Off
* ("Customize for this chat" switch) the list shows the workspace's defaults
* read-only and the chat sends nothing; on, every row is a toggle and the chat
* sends its own `agent.capabilities`. Workspace connectors opens the
* connectors list nested under it. Product words only; no tool ids.
*/
import { CheckIcon, ChevronRightIcon, LockIcon } from "lucide-react";
import type { ReactNode } from "react";
import { ConnectorAction } from "../../ui/composer-menu-action";
import { ComposerMenuHeader, ComposerMenuSwitchIndicator } from "../../ui/composer-menu";
import {
AGENT_CAPABILITY_GROUPS,
UNAVAILABLE_CAPABILITY_REASON,
capabilityDescription,
capabilityLabel,
capabilitySummary,
effectiveCapabilityOn,
withCapability,
type AgentCapabilityDraft,
type AgentCapabilityId,
type CapabilityAvailability,
} from "../lib/agent-capabilities";
import { cn } from "../lib/utils";
export type ComposerAgentCapabilities = {
/** "Customize for this chat" is on: the chat sends its own capabilities. */
customized: boolean;
/** What the chat gets: its own values when customized, else the workspace's. */
draft: AgentCapabilityDraft;
availability: CapabilityAvailability;
onCustomizedChange: (customized: boolean) => void;
onChange: (draft: AgentCapabilityDraft) => void;
disabled?: boolean | undefined;
};
export function ComposerCapabilitiesMenuBody(props: {
capabilities: ComposerAgentCapabilities;
presentation?: "menu" | "dialog" | undefined;
leading?: ReactNode | undefined;
/** Number of connected apps on for this chat, shown under Workspace connectors. */
connectorsSelected: number;
connectorsTotal: number;
onOpenConnectors: () => void;
}) {
const { capabilities } = props;
const { customized, draft, availability } = capabilities;
const set = (id: AgentCapabilityId, value: boolean | "read" | "manage" | false) =>
capabilities.onChange(withCapability(draft, id, value));
return (
<>
{group.label}
{group.capabilities.map((id) => { const available = availability.isAvailable(id); const on = effectiveCapabilityOn(draft.values, id, availability); const editable = customized && available && !capabilities.disabled; // The menu stays scannable: labels only, plus the one line that // changes the decision (unavailable, or which apps are on). const note = !available ? (