@agent-native/dispatch 0.24.2 → 0.24.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"agents-panel.d.ts","sourceRoot":"","sources":["../../src/components/agents-panel.tsx"],"names":[],"mappings":"AAkBA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;CAC/B;AA4CD,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB,mDAuRA"}
1
+ {"version":3,"file":"agents-panel.d.ts","sourceRoot":"","sources":["../../src/components/agents-panel.tsx"],"names":[],"mappings":"AAmBA,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,QAAQ,GAAG,UAAU,CAAC;CAC/B;AA4CD,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,SAAS,GACV,EAAE;IACD,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB,mDA+SA"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { agentNativePath } from "@agent-native/core/client/api-path";
3
+ import { useOrgRole } from "@agent-native/core/client/org";
3
4
  import { IconExternalLink, IconTrash } from "@tabler/icons-react";
4
5
  import { useRef, useState } from "react";
5
6
  import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "./ui/alert-dialog.js";
@@ -46,6 +47,10 @@ function validateAgentForm(name, url) {
46
47
  return errors;
47
48
  }
48
49
  export function AgentsPanel({ agents, onRefresh, }) {
50
+ const { org, isLoading: orgLoading, error: orgError } = useOrgRole();
51
+ const canManageSharedAgents = !orgLoading &&
52
+ !orgError &&
53
+ (!org?.orgId || org.role === "owner" || org.role === "admin");
49
54
  const [name, setName] = useState("");
50
55
  const [url, setUrl] = useState("");
51
56
  const [description, setDescription] = useState("");
@@ -117,12 +122,12 @@ export function AgentsPanel({ agents, onRefresh, }) {
117
122
  if (res.ok)
118
123
  onRefresh();
119
124
  };
120
- return (_jsx("section", { className: "rounded-2xl bg-card p-5", children: _jsxs("div", { className: "grid gap-4 xl:grid-cols-[minmax(0,1fr)_320px]", children: [_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Available by default" }), _jsxs("div", { className: "mt-2 flex flex-wrap gap-2", children: [builtinAgents.map((agent) => (_jsxs("div", { className: "inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-xs text-muted-foreground", children: [_jsx("span", { className: "h-2 w-2 rounded-full", style: { backgroundColor: agent.color } }), _jsx("span", { children: agent.name })] }, agent.id))), builtinAgents.length === 0 && (_jsx("div", { className: "rounded-xl border border-dashed px-4 py-6 text-sm text-muted-foreground", children: "No default agents detected." }))] })] }), _jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Added in this workspace" }), _jsxs("div", { className: "mt-2 space-y-2", children: [workspaceAgents.map((agent) => (_jsx("div", { className: "flex items-start justify-between gap-3 rounded-xl border bg-muted/30 px-4 py-3", children: _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: agent.name }), agent.description ? (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: agent.description })) : null, _jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: _jsxs("a", { href: agent.url, target: "_blank", rel: "noreferrer", className: "inline-flex items-center gap-1 hover:text-foreground", children: [agent.url, _jsx(IconExternalLink, { className: "h-3 w-3" })] }) })] }) }, agent.id))), customAgents.map((agent) => (_jsxs("div", { className: "flex items-start justify-between gap-3 rounded-xl border bg-muted/30 px-4 py-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: agent.name }), agent.description ? (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: agent.description })) : null, _jsxs("div", { className: "mt-1 flex items-center gap-2 text-xs text-muted-foreground", children: [_jsxs("a", { href: agent.url, target: "_blank", rel: "noreferrer", className: "inline-flex items-center gap-1 hover:text-foreground", children: [agent.url, _jsx(IconExternalLink, { className: "h-3 w-3" })] }), _jsx("span", { children: "\u00B7" }), _jsx("span", { children: agent.scope || "shared" })] })] }), _jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", children: _jsx(IconTrash, { className: "h-4 w-4" }) }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Remove this agent?" }), _jsxs(AlertDialogDescription, { children: ["\u201C", agent.name, "\u201D will be removed from the workspace. Any jobs or chats that delegate to it will stop working."] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Cancel" }), _jsx(AlertDialogAction, { onClick: () => handleDelete(agent.resourceId), children: "Remove" })] })] })] })] }, agent.id))), workspaceAgents.length === 0 && customAgents.length === 0 && (_jsx("div", { className: "rounded-xl border border-dashed px-4 py-6 text-sm text-muted-foreground", children: "No extra agents added yet." }))] })] })] }), _jsxs("div", { className: "rounded-xl border bg-muted/20 p-4", children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Add external agent" }), _jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: "Add another A2A-compatible app by saving its agent endpoint here." }), _jsxs("form", { className: "mt-4 space-y-3", onSubmit: handleAdd, noValidate: true, children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Input, { ref: nameRef, value: name, onChange: (event) => {
125
+ return (_jsx("section", { className: "rounded-2xl bg-card p-5", children: _jsxs("div", { className: "grid gap-4 xl:grid-cols-[minmax(0,1fr)_320px]", children: [_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Available by default" }), _jsxs("div", { className: "mt-2 flex flex-wrap gap-2", children: [builtinAgents.map((agent) => (_jsxs("div", { className: "inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-xs text-muted-foreground", children: [_jsx("span", { className: "h-2 w-2 rounded-full", style: { backgroundColor: agent.color } }), _jsx("span", { children: agent.name })] }, agent.id))), builtinAgents.length === 0 && (_jsx("div", { className: "rounded-xl border border-dashed px-4 py-6 text-sm text-muted-foreground", children: "No default agents detected." }))] })] }), _jsxs("div", { children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Added in this workspace" }), _jsxs("div", { className: "mt-2 space-y-2", children: [workspaceAgents.map((agent) => (_jsx("div", { className: "flex items-start justify-between gap-3 rounded-xl border bg-muted/30 px-4 py-3", children: _jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: agent.name }), agent.description ? (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: agent.description })) : null, _jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: _jsxs("a", { href: agent.url, target: "_blank", rel: "noreferrer", className: "inline-flex items-center gap-1 hover:text-foreground", children: [agent.url, _jsx(IconExternalLink, { className: "h-3 w-3" })] }) })] }) }, agent.id))), customAgents.map((agent) => (_jsxs("div", { className: "flex items-start justify-between gap-3 rounded-xl border bg-muted/30 px-4 py-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: agent.name }), agent.description ? (_jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: agent.description })) : null, _jsxs("div", { className: "mt-1 flex items-center gap-2 text-xs text-muted-foreground", children: [_jsxs("a", { href: agent.url, target: "_blank", rel: "noreferrer", className: "inline-flex items-center gap-1 hover:text-foreground", children: [agent.url, _jsx(IconExternalLink, { className: "h-3 w-3" })] }), _jsx("span", { children: "\u00B7" }), _jsx("span", { children: agent.scope || "shared" })] })] }), canManageSharedAgents && (_jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon", children: _jsx(IconTrash, { className: "h-4 w-4" }) }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Remove this agent?" }), _jsxs(AlertDialogDescription, { children: ["\u201C", agent.name, "\u201D will be removed from the workspace. Any jobs or chats that delegate to it will stop working."] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { children: "Cancel" }), _jsx(AlertDialogAction, { onClick: () => handleDelete(agent.resourceId), children: "Remove" })] })] })] }))] }, agent.id))), workspaceAgents.length === 0 && customAgents.length === 0 && (_jsx("div", { className: "rounded-xl border border-dashed px-4 py-6 text-sm text-muted-foreground", children: "No extra agents added yet." }))] })] })] }), _jsxs("div", { className: "rounded-xl border bg-muted/20 p-4", children: [_jsx("div", { className: "text-sm font-medium text-foreground", children: "Add external agent" }), canManageSharedAgents ? (_jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: "Add another A2A-compatible app by saving its agent endpoint here." })) : !orgLoading ? (_jsx("p", { className: "mt-1 text-xs leading-relaxed text-muted-foreground", children: "Only workspace owners and admins can add shared agents." })) : null, _jsxs("form", { className: `mt-4 space-y-3 ${canManageSharedAgents ? "" : "hidden"}`, onSubmit: handleAdd, noValidate: true, children: [_jsxs("div", { className: "space-y-1.5", children: [_jsx(Input, { ref: nameRef, value: name, onChange: (event) => {
121
126
  setName(event.target.value);
122
127
  setErrors((current) => ({ ...current, name: undefined }));
123
128
  }, placeholder: "Name", "aria-invalid": Boolean(errors.name), "aria-describedby": errors.name ? "external-agent-name-error" : undefined }), errors.name ? (_jsx("p", { id: "external-agent-name-error", className: "text-xs font-medium text-destructive", children: errors.name })) : null] }), _jsxs("div", { className: "space-y-1.5", children: [_jsx(Input, { value: url, onChange: (event) => {
124
129
  setUrl(event.target.value);
125
130
  setErrors((current) => ({ ...current, url: undefined }));
126
- }, placeholder: "https://app.example.com", "aria-invalid": Boolean(errors.url), "aria-describedby": errors.url ? "external-agent-url-error" : undefined }), errors.url ? (_jsx("p", { id: "external-agent-url-error", className: "text-xs font-medium text-destructive", children: errors.url })) : null] }), _jsx(Input, { value: description, onChange: (event) => setDescription(event.target.value), placeholder: "Description (optional)" }), errors.form ? (_jsx("p", { className: "text-xs font-medium text-destructive", children: errors.form })) : null, _jsx(Button, { type: "submit", className: "w-full", disabled: saving, children: saving ? "Saving..." : "Add agent" })] })] })] }) }));
131
+ }, placeholder: "https://app.example.com", "aria-invalid": Boolean(errors.url), "aria-describedby": errors.url ? "external-agent-url-error" : undefined }), errors.url ? (_jsx("p", { id: "external-agent-url-error", className: "text-xs font-medium text-destructive", children: errors.url })) : null] }), _jsx(Input, { value: description, onChange: (event) => setDescription(event.target.value), placeholder: "Description (optional)" }), errors.form ? (_jsx("p", { className: "text-xs font-medium text-destructive", children: errors.form })) : null, _jsx(Button, { type: "submit", className: "w-full", disabled: saving || !canManageSharedAgents, children: saving ? "Saving..." : "Add agent" })] })] })] }) }));
127
132
  }
128
133
  //# sourceMappingURL=agents-panel.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"agents-panel.js","sourceRoot":"","sources":["../../src/components/agents-panel.tsx"],"names":[],"mappings":"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","sourcesContent":["import { agentNativePath } from \"@agent-native/core/client/api-path\";\nimport { IconExternalLink, IconTrash } from \"@tabler/icons-react\";\nimport { useRef, useState, type FormEvent } from \"react\";\n\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"./ui/alert-dialog\";\nimport { Button } from \"./ui/button\";\nimport { Input } from \"./ui/input\";\n\nexport interface ConnectedAgent {\n id: string;\n name: string;\n description: string;\n url: string;\n color: string;\n source: \"builtin\" | \"custom\" | \"workspace\";\n resourceId?: string;\n path?: string;\n scope?: \"shared\" | \"personal\";\n}\n\ntype AgentFormErrors = Partial<Record<\"name\" | \"url\" | \"form\", string>>;\n\nfunction slugifyAgentName(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nfunction validateAgentForm(name: string, url: string): AgentFormErrors {\n const errors: AgentFormErrors = {};\n const trimmedName = name.trim();\n const trimmedUrl = url.trim();\n\n if (!trimmedName) {\n errors.name = \"Agent name is required.\";\n } else if (!slugifyAgentName(trimmedName)) {\n errors.name = \"Agent name must include at least one letter or number.\";\n }\n\n if (!trimmedUrl) {\n errors.url = \"Agent endpoint URL is required.\";\n } else {\n try {\n const parsed = new URL(trimmedUrl);\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") {\n errors.url = \"Use an http:// or https:// endpoint URL.\";\n } else if (!parsed.hostname) {\n errors.url = \"Enter a complete endpoint URL with a host.\";\n } else if (parsed.username || parsed.password) {\n errors.url = \"Do not include credentials in the endpoint URL.\";\n }\n } catch {\n errors.url =\n \"Enter a valid endpoint URL, such as https://app.example.com.\";\n }\n }\n\n return errors;\n}\n\nexport function AgentsPanel({\n agents,\n onRefresh,\n}: {\n agents: ConnectedAgent[];\n onRefresh: () => void;\n}) {\n const [name, setName] = useState(\"\");\n const [url, setUrl] = useState(\"\");\n const [description, setDescription] = useState(\"\");\n const [saving, setSaving] = useState(false);\n const [errors, setErrors] = useState<AgentFormErrors>({});\n const nameRef = useRef<HTMLInputElement>(null);\n\n const customAgents = agents.filter((agent) => agent.source === \"custom\");\n const workspaceAgents = agents.filter(\n (agent) => agent.source === \"workspace\",\n );\n const builtinAgents = agents.filter((agent) => agent.source === \"builtin\");\n\n const handleAdd = async (event?: FormEvent<HTMLFormElement>) => {\n event?.preventDefault();\n const trimmedName = name.trim();\n const trimmedUrl = url.trim();\n const nextErrors = validateAgentForm(trimmedName, trimmedUrl);\n if (Object.keys(nextErrors).length > 0) {\n setErrors(nextErrors);\n return;\n }\n\n const id = slugifyAgentName(trimmedName);\n const agentJson = JSON.stringify(\n {\n id,\n name: trimmedName,\n description: description.trim() || undefined,\n url: trimmedUrl,\n color: \"#6B7280\",\n },\n null,\n 2,\n );\n\n setSaving(true);\n try {\n const res = await fetch(agentNativePath(\"/_agent-native/resources\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n path: `remote-agents/${id}.json`,\n content: agentJson,\n shared: true,\n }),\n });\n if (res.ok) {\n setName(\"\");\n setUrl(\"\");\n setDescription(\"\");\n setErrors({});\n onRefresh();\n nameRef.current?.focus();\n } else {\n setErrors({\n form: `Could not add agent. Request failed with ${res.status}.`,\n });\n }\n } catch (error) {\n setErrors({\n form:\n error instanceof Error\n ? error.message\n : \"Could not add agent. Please try again.\",\n });\n } finally {\n setSaving(false);\n }\n };\n\n const handleDelete = async (resourceId?: string) => {\n if (!resourceId) return;\n const res = await fetch(\n agentNativePath(`/_agent-native/resources/${resourceId}`),\n {\n method: \"DELETE\",\n },\n );\n if (res.ok) onRefresh();\n };\n\n return (\n <section className=\"rounded-2xl bg-card p-5\">\n <div className=\"grid gap-4 xl:grid-cols-[minmax(0,1fr)_320px]\">\n <div className=\"space-y-4\">\n <div>\n <div className=\"text-sm font-medium text-foreground\">\n Available by default\n </div>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {builtinAgents.map((agent) => (\n <div\n key={agent.id}\n className=\"inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-xs text-muted-foreground\"\n >\n <span\n className=\"h-2 w-2 rounded-full\"\n style={{ backgroundColor: agent.color }}\n />\n <span>{agent.name}</span>\n </div>\n ))}\n {builtinAgents.length === 0 && (\n <div className=\"rounded-xl border border-dashed px-4 py-6 text-sm text-muted-foreground\">\n No default agents detected.\n </div>\n )}\n </div>\n </div>\n\n <div>\n <div className=\"text-sm font-medium text-foreground\">\n Added in this workspace\n </div>\n <div className=\"mt-2 space-y-2\">\n {workspaceAgents.map((agent) => (\n <div\n key={agent.id}\n className=\"flex items-start justify-between gap-3 rounded-xl border bg-muted/30 px-4 py-3\"\n >\n <div className=\"min-w-0\">\n <div className=\"text-sm font-medium text-foreground\">\n {agent.name}\n </div>\n {agent.description ? (\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {agent.description}\n </div>\n ) : null}\n <div className=\"mt-1 text-xs text-muted-foreground\">\n <a\n href={agent.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 hover:text-foreground\"\n >\n {agent.url}\n <IconExternalLink className=\"h-3 w-3\" />\n </a>\n </div>\n </div>\n </div>\n ))}\n {customAgents.map((agent) => (\n <div\n key={agent.id}\n className=\"flex items-start justify-between gap-3 rounded-xl border bg-muted/30 px-4 py-3\"\n >\n <div className=\"min-w-0\">\n <div className=\"text-sm font-medium text-foreground\">\n {agent.name}\n </div>\n {agent.description ? (\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {agent.description}\n </div>\n ) : null}\n <div className=\"mt-1 flex items-center gap-2 text-xs text-muted-foreground\">\n <a\n href={agent.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 hover:text-foreground\"\n >\n {agent.url}\n <IconExternalLink className=\"h-3 w-3\" />\n </a>\n <span>·</span>\n <span>{agent.scope || \"shared\"}</span>\n </div>\n </div>\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\">\n <IconTrash className=\"h-4 w-4\" />\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>Remove this agent?</AlertDialogTitle>\n <AlertDialogDescription>\n “{agent.name}” will be removed from the workspace. Any\n jobs or chats that delegate to it will stop working.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={() => handleDelete(agent.resourceId)}\n >\n Remove\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n </div>\n ))}\n {workspaceAgents.length === 0 && customAgents.length === 0 && (\n <div className=\"rounded-xl border border-dashed px-4 py-6 text-sm text-muted-foreground\">\n No extra agents added yet.\n </div>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"rounded-xl border bg-muted/20 p-4\">\n <div className=\"text-sm font-medium text-foreground\">\n Add external agent\n </div>\n <p className=\"mt-1 text-xs leading-relaxed text-muted-foreground\">\n Add another A2A-compatible app by saving its agent endpoint here.\n </p>\n <form className=\"mt-4 space-y-3\" onSubmit={handleAdd} noValidate>\n <div className=\"space-y-1.5\">\n <Input\n ref={nameRef}\n value={name}\n onChange={(event) => {\n setName(event.target.value);\n setErrors((current) => ({ ...current, name: undefined }));\n }}\n placeholder=\"Name\"\n aria-invalid={Boolean(errors.name)}\n aria-describedby={\n errors.name ? \"external-agent-name-error\" : undefined\n }\n />\n {errors.name ? (\n <p\n id=\"external-agent-name-error\"\n className=\"text-xs font-medium text-destructive\"\n >\n {errors.name}\n </p>\n ) : null}\n </div>\n <div className=\"space-y-1.5\">\n <Input\n value={url}\n onChange={(event) => {\n setUrl(event.target.value);\n setErrors((current) => ({ ...current, url: undefined }));\n }}\n placeholder=\"https://app.example.com\"\n aria-invalid={Boolean(errors.url)}\n aria-describedby={\n errors.url ? \"external-agent-url-error\" : undefined\n }\n />\n {errors.url ? (\n <p\n id=\"external-agent-url-error\"\n className=\"text-xs font-medium text-destructive\"\n >\n {errors.url}\n </p>\n ) : null}\n </div>\n <Input\n value={description}\n onChange={(event) => setDescription(event.target.value)}\n placeholder=\"Description (optional)\"\n />\n {errors.form ? (\n <p className=\"text-xs font-medium text-destructive\">\n {errors.form}\n </p>\n ) : null}\n <Button type=\"submit\" className=\"w-full\" disabled={saving}>\n {saving ? \"Saving...\" : \"Add agent\"}\n </Button>\n </form>\n </div>\n </div>\n </section>\n );\n}\n"]}
1
+ {"version":3,"file":"agents-panel.js","sourceRoot":"","sources":["../../src/components/agents-panel.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAkB,MAAM,OAAO,CAAC;AAEzD,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAgBnC,SAAS,gBAAgB,CAAC,KAAa;IACrC,OAAO,KAAK;SACT,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAY,EAAE,GAAW;IAClD,MAAM,MAAM,GAAoB,EAAE,CAAC;IACnC,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAChC,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAE9B,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,CAAC,IAAI,GAAG,yBAAyB,CAAC;IAC1C,CAAC;SAAM,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,EAAE,CAAC;QAC1C,MAAM,CAAC,IAAI,GAAG,wDAAwD,CAAC;IACzE,CAAC;IAED,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,CAAC,GAAG,GAAG,iCAAiC,CAAC;IACjD,CAAC;SAAM,CAAC;QACN,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;YACnC,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;gBAChE,MAAM,CAAC,GAAG,GAAG,0CAA0C,CAAC;YAC1D,CAAC;iBAAM,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAC5B,MAAM,CAAC,GAAG,GAAG,4CAA4C,CAAC;YAC5D,CAAC;iBAAM,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;gBAC9C,MAAM,CAAC,GAAG,GAAG,iDAAiD,CAAC;YACjE,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,CAAC,GAAG;gBACR,8DAA8D,CAAC;QACnE,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,EAC1B,MAAM,EACN,SAAS,GAIV;IACC,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,UAAU,EAAE,CAAC;IACrE,MAAM,qBAAqB,GACzB,CAAC,UAAU;QACX,CAAC,QAAQ;QACT,CAAC,CAAC,GAAG,EAAE,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;IAChE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACrC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnC,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;IACnD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,QAAQ,CAAkB,EAAE,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,MAAM,CAAmB,IAAI,CAAC,CAAC;IAE/C,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;IACzE,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,CACnC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,WAAW,CACxC,CAAC;IACF,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC;IAE3E,MAAM,SAAS,GAAG,KAAK,EAAE,KAAkC,EAAE,EAAE;QAC7D,KAAK,EAAE,cAAc,EAAE,CAAC;QACxB,MAAM,WAAW,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAChC,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,UAAU,GAAG,iBAAiB,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;QAC9D,IAAI,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvC,SAAS,CAAC,UAAU,CAAC,CAAC;YACtB,OAAO;QACT,CAAC;QAED,MAAM,EAAE,GAAG,gBAAgB,CAAC,WAAW,CAAC,CAAC;QACzC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAC9B;YACE,EAAE;YACF,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,WAAW,CAAC,IAAI,EAAE,IAAI,SAAS;YAC5C,GAAG,EAAE,UAAU;YACf,KAAK,EAAE,SAAS;SACjB,EACD,IAAI,EACJ,CAAC,CACF,CAAC;QAEF,SAAS,CAAC,IAAI,CAAC,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC,0BAA0B,CAAC,EAAE;gBACnE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,IAAI,EAAE,iBAAiB,EAAE,OAAO;oBAChC,OAAO,EAAE,SAAS;oBAClB,MAAM,EAAE,IAAI;iBACb,CAAC;aACH,CAAC,CAAC;YACH,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;gBACX,OAAO,CAAC,EAAE,CAAC,CAAC;gBACZ,MAAM,CAAC,EAAE,CAAC,CAAC;gBACX,cAAc,CAAC,EAAE,CAAC,CAAC;gBACnB,SAAS,CAAC,EAAE,CAAC,CAAC;gBACd,SAAS,EAAE,CAAC;gBACZ,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACN,SAAS,CAAC;oBACR,IAAI,EAAE,4CAA4C,GAAG,CAAC,MAAM,GAAG;iBAChE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,CAAC;gBACR,IAAI,EACF,KAAK,YAAY,KAAK;oBACpB,CAAC,CAAC,KAAK,CAAC,OAAO;oBACf,CAAC,CAAC,wCAAwC;aAC/C,CAAC,CAAC;QACL,CAAC;gBAAS,CAAC;YACT,SAAS,CAAC,KAAK,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,YAAY,GAAG,KAAK,EAAE,UAAmB,EAAE,EAAE;QACjD,IAAI,CAAC,UAAU;YAAE,OAAO;QACxB,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,eAAe,CAAC,4BAA4B,UAAU,EAAE,CAAC,EACzD;YACE,MAAM,EAAE,QAAQ;SACjB,CACF,CAAC;QACF,IAAI,GAAG,CAAC,EAAE;YAAE,SAAS,EAAE,CAAC;IAC1B,CAAC,CAAC;IAEF,OAAO,CACL,kBAAS,SAAS,EAAC,yBAAyB,YAC1C,eAAK,SAAS,EAAC,+CAA+C,aAC5D,eAAK,SAAS,EAAC,WAAW,aACxB,0BACE,cAAK,SAAS,EAAC,qCAAqC,qCAE9C,EACN,eAAK,SAAS,EAAC,2BAA2B,aACvC,aAAa,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC5B,eAEE,SAAS,EAAC,8FAA8F,aAExG,eACE,SAAS,EAAC,sBAAsB,EAChC,KAAK,EAAE,EAAE,eAAe,EAAE,KAAK,CAAC,KAAK,EAAE,GACvC,EACF,yBAAO,KAAK,CAAC,IAAI,GAAQ,KAPpB,KAAK,CAAC,EAAE,CAQT,CACP,CAAC,EACD,aAAa,CAAC,MAAM,KAAK,CAAC,IAAI,CAC7B,cAAK,SAAS,EAAC,yEAAyE,4CAElF,CACP,IACG,IACF,EAEN,0BACE,cAAK,SAAS,EAAC,qCAAqC,wCAE9C,EACN,eAAK,SAAS,EAAC,gBAAgB,aAC5B,eAAe,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC9B,cAEE,SAAS,EAAC,gFAAgF,YAE1F,eAAK,SAAS,EAAC,SAAS,aACtB,cAAK,SAAS,EAAC,qCAAqC,YACjD,KAAK,CAAC,IAAI,GACP,EACL,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CACnB,cAAK,SAAS,EAAC,oCAAoC,YAChD,KAAK,CAAC,WAAW,GACd,CACP,CAAC,CAAC,CAAC,IAAI,EACR,cAAK,SAAS,EAAC,oCAAoC,YACjD,aACE,IAAI,EAAE,KAAK,CAAC,GAAG,EACf,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,YAAY,EAChB,SAAS,EAAC,sDAAsD,aAE/D,KAAK,CAAC,GAAG,EACV,KAAC,gBAAgB,IAAC,SAAS,EAAC,SAAS,GAAG,IACtC,GACA,IACF,IAvBD,KAAK,CAAC,EAAE,CAwBT,CACP,CAAC,EACD,YAAY,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAC3B,eAEE,SAAS,EAAC,gFAAgF,aAE1F,eAAK,SAAS,EAAC,SAAS,aACtB,cAAK,SAAS,EAAC,qCAAqC,YACjD,KAAK,CAAC,IAAI,GACP,EACL,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CACnB,cAAK,SAAS,EAAC,oCAAoC,YAChD,KAAK,CAAC,WAAW,GACd,CACP,CAAC,CAAC,CAAC,IAAI,EACR,eAAK,SAAS,EAAC,4DAA4D,aACzE,aACE,IAAI,EAAE,KAAK,CAAC,GAAG,EACf,MAAM,EAAC,QAAQ,EACf,GAAG,EAAC,YAAY,EAChB,SAAS,EAAC,sDAAsD,aAE/D,KAAK,CAAC,GAAG,EACV,KAAC,gBAAgB,IAAC,SAAS,EAAC,SAAS,GAAG,IACtC,EACJ,oCAAc,EACd,yBAAO,KAAK,CAAC,KAAK,IAAI,QAAQ,GAAQ,IAClC,IACF,EACL,qBAAqB,IAAI,CACxB,MAAC,WAAW,eACV,KAAC,kBAAkB,IAAC,OAAO,kBACzB,KAAC,MAAM,IAAC,OAAO,EAAC,OAAO,EAAC,IAAI,EAAC,MAAM,YACjC,KAAC,SAAS,IAAC,SAAS,EAAC,SAAS,GAAG,GAC1B,GACU,EACrB,MAAC,kBAAkB,eACjB,MAAC,iBAAiB,eAChB,KAAC,gBAAgB,qCAEE,EACnB,MAAC,sBAAsB,yBACnB,KAAK,CAAC,IAAI,2GAGW,IACP,EACpB,MAAC,iBAAiB,eAChB,KAAC,iBAAiB,yBAA2B,EAC7C,KAAC,iBAAiB,IAChB,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,UAAU,CAAC,uBAG3B,IACF,IACD,IACT,CACf,KAtDI,KAAK,CAAC,EAAE,CAuDT,CACP,CAAC,EACD,eAAe,CAAC,MAAM,KAAK,CAAC,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,CAC5D,cAAK,SAAS,EAAC,yEAAyE,2CAElF,CACP,IACG,IACF,IACF,EAEN,eAAK,SAAS,EAAC,mCAAmC,aAChD,cAAK,SAAS,EAAC,qCAAqC,mCAE9C,EACL,qBAAqB,CAAC,CAAC,CAAC,CACvB,YAAG,SAAS,EAAC,oDAAoD,kFAE7D,CACL,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAChB,YAAG,SAAS,EAAC,oDAAoD,wEAE7D,CACL,CAAC,CAAC,CAAC,IAAI,EACR,gBACE,SAAS,EAAE,kBAAkB,qBAAqB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,EACpE,QAAQ,EAAE,SAAS,EACnB,UAAU,mBAEV,eAAK,SAAS,EAAC,aAAa,aAC1B,KAAC,KAAK,IACJ,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,IAAI,EACX,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gDAClB,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gDAC5B,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;4CAC5D,CAAC,EACD,WAAW,EAAC,MAAM,kBACJ,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,sBAEhC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,2BAA2B,CAAC,CAAC,CAAC,SAAS,GAEvD,EACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CACb,YACE,EAAE,EAAC,2BAA2B,EAC9B,SAAS,EAAC,sCAAsC,YAE/C,MAAM,CAAC,IAAI,GACV,CACL,CAAC,CAAC,CAAC,IAAI,IACJ,EACN,eAAK,SAAS,EAAC,aAAa,aAC1B,KAAC,KAAK,IACJ,KAAK,EAAE,GAAG,EACV,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gDAClB,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gDAC3B,SAAS,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;4CAC3D,CAAC,EACD,WAAW,EAAC,yBAAyB,kBACvB,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,sBAE/B,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,SAAS,GAErD,EACD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CACZ,YACE,EAAE,EAAC,0BAA0B,EAC7B,SAAS,EAAC,sCAAsC,YAE/C,MAAM,CAAC,GAAG,GACT,CACL,CAAC,CAAC,CAAC,IAAI,IACJ,EACN,KAAC,KAAK,IACJ,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,EACvD,WAAW,EAAC,wBAAwB,GACpC,EACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CACb,YAAG,SAAS,EAAC,sCAAsC,YAChD,MAAM,CAAC,IAAI,GACV,CACL,CAAC,CAAC,CAAC,IAAI,EACR,KAAC,MAAM,IACL,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,QAAQ,EAClB,QAAQ,EAAE,MAAM,IAAI,CAAC,qBAAqB,YAEzC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,GAC5B,IACJ,IACH,IACF,GACE,CACX,CAAC;AACJ,CAAC","sourcesContent":["import { agentNativePath } from \"@agent-native/core/client/api-path\";\nimport { useOrgRole } from \"@agent-native/core/client/org\";\nimport { IconExternalLink, IconTrash } from \"@tabler/icons-react\";\nimport { useRef, useState, type FormEvent } from \"react\";\n\nimport {\n AlertDialog,\n AlertDialogAction,\n AlertDialogCancel,\n AlertDialogContent,\n AlertDialogDescription,\n AlertDialogFooter,\n AlertDialogHeader,\n AlertDialogTitle,\n AlertDialogTrigger,\n} from \"./ui/alert-dialog\";\nimport { Button } from \"./ui/button\";\nimport { Input } from \"./ui/input\";\n\nexport interface ConnectedAgent {\n id: string;\n name: string;\n description: string;\n url: string;\n color: string;\n source: \"builtin\" | \"custom\" | \"workspace\";\n resourceId?: string;\n path?: string;\n scope?: \"shared\" | \"personal\";\n}\n\ntype AgentFormErrors = Partial<Record<\"name\" | \"url\" | \"form\", string>>;\n\nfunction slugifyAgentName(value: string): string {\n return value\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\nfunction validateAgentForm(name: string, url: string): AgentFormErrors {\n const errors: AgentFormErrors = {};\n const trimmedName = name.trim();\n const trimmedUrl = url.trim();\n\n if (!trimmedName) {\n errors.name = \"Agent name is required.\";\n } else if (!slugifyAgentName(trimmedName)) {\n errors.name = \"Agent name must include at least one letter or number.\";\n }\n\n if (!trimmedUrl) {\n errors.url = \"Agent endpoint URL is required.\";\n } else {\n try {\n const parsed = new URL(trimmedUrl);\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") {\n errors.url = \"Use an http:// or https:// endpoint URL.\";\n } else if (!parsed.hostname) {\n errors.url = \"Enter a complete endpoint URL with a host.\";\n } else if (parsed.username || parsed.password) {\n errors.url = \"Do not include credentials in the endpoint URL.\";\n }\n } catch {\n errors.url =\n \"Enter a valid endpoint URL, such as https://app.example.com.\";\n }\n }\n\n return errors;\n}\n\nexport function AgentsPanel({\n agents,\n onRefresh,\n}: {\n agents: ConnectedAgent[];\n onRefresh: () => void;\n}) {\n const { org, isLoading: orgLoading, error: orgError } = useOrgRole();\n const canManageSharedAgents =\n !orgLoading &&\n !orgError &&\n (!org?.orgId || org.role === \"owner\" || org.role === \"admin\");\n const [name, setName] = useState(\"\");\n const [url, setUrl] = useState(\"\");\n const [description, setDescription] = useState(\"\");\n const [saving, setSaving] = useState(false);\n const [errors, setErrors] = useState<AgentFormErrors>({});\n const nameRef = useRef<HTMLInputElement>(null);\n\n const customAgents = agents.filter((agent) => agent.source === \"custom\");\n const workspaceAgents = agents.filter(\n (agent) => agent.source === \"workspace\",\n );\n const builtinAgents = agents.filter((agent) => agent.source === \"builtin\");\n\n const handleAdd = async (event?: FormEvent<HTMLFormElement>) => {\n event?.preventDefault();\n const trimmedName = name.trim();\n const trimmedUrl = url.trim();\n const nextErrors = validateAgentForm(trimmedName, trimmedUrl);\n if (Object.keys(nextErrors).length > 0) {\n setErrors(nextErrors);\n return;\n }\n\n const id = slugifyAgentName(trimmedName);\n const agentJson = JSON.stringify(\n {\n id,\n name: trimmedName,\n description: description.trim() || undefined,\n url: trimmedUrl,\n color: \"#6B7280\",\n },\n null,\n 2,\n );\n\n setSaving(true);\n try {\n const res = await fetch(agentNativePath(\"/_agent-native/resources\"), {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n path: `remote-agents/${id}.json`,\n content: agentJson,\n shared: true,\n }),\n });\n if (res.ok) {\n setName(\"\");\n setUrl(\"\");\n setDescription(\"\");\n setErrors({});\n onRefresh();\n nameRef.current?.focus();\n } else {\n setErrors({\n form: `Could not add agent. Request failed with ${res.status}.`,\n });\n }\n } catch (error) {\n setErrors({\n form:\n error instanceof Error\n ? error.message\n : \"Could not add agent. Please try again.\",\n });\n } finally {\n setSaving(false);\n }\n };\n\n const handleDelete = async (resourceId?: string) => {\n if (!resourceId) return;\n const res = await fetch(\n agentNativePath(`/_agent-native/resources/${resourceId}`),\n {\n method: \"DELETE\",\n },\n );\n if (res.ok) onRefresh();\n };\n\n return (\n <section className=\"rounded-2xl bg-card p-5\">\n <div className=\"grid gap-4 xl:grid-cols-[minmax(0,1fr)_320px]\">\n <div className=\"space-y-4\">\n <div>\n <div className=\"text-sm font-medium text-foreground\">\n Available by default\n </div>\n <div className=\"mt-2 flex flex-wrap gap-2\">\n {builtinAgents.map((agent) => (\n <div\n key={agent.id}\n className=\"inline-flex items-center gap-2 rounded-full border px-3 py-1.5 text-xs text-muted-foreground\"\n >\n <span\n className=\"h-2 w-2 rounded-full\"\n style={{ backgroundColor: agent.color }}\n />\n <span>{agent.name}</span>\n </div>\n ))}\n {builtinAgents.length === 0 && (\n <div className=\"rounded-xl border border-dashed px-4 py-6 text-sm text-muted-foreground\">\n No default agents detected.\n </div>\n )}\n </div>\n </div>\n\n <div>\n <div className=\"text-sm font-medium text-foreground\">\n Added in this workspace\n </div>\n <div className=\"mt-2 space-y-2\">\n {workspaceAgents.map((agent) => (\n <div\n key={agent.id}\n className=\"flex items-start justify-between gap-3 rounded-xl border bg-muted/30 px-4 py-3\"\n >\n <div className=\"min-w-0\">\n <div className=\"text-sm font-medium text-foreground\">\n {agent.name}\n </div>\n {agent.description ? (\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {agent.description}\n </div>\n ) : null}\n <div className=\"mt-1 text-xs text-muted-foreground\">\n <a\n href={agent.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 hover:text-foreground\"\n >\n {agent.url}\n <IconExternalLink className=\"h-3 w-3\" />\n </a>\n </div>\n </div>\n </div>\n ))}\n {customAgents.map((agent) => (\n <div\n key={agent.id}\n className=\"flex items-start justify-between gap-3 rounded-xl border bg-muted/30 px-4 py-3\"\n >\n <div className=\"min-w-0\">\n <div className=\"text-sm font-medium text-foreground\">\n {agent.name}\n </div>\n {agent.description ? (\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {agent.description}\n </div>\n ) : null}\n <div className=\"mt-1 flex items-center gap-2 text-xs text-muted-foreground\">\n <a\n href={agent.url}\n target=\"_blank\"\n rel=\"noreferrer\"\n className=\"inline-flex items-center gap-1 hover:text-foreground\"\n >\n {agent.url}\n <IconExternalLink className=\"h-3 w-3\" />\n </a>\n <span>·</span>\n <span>{agent.scope || \"shared\"}</span>\n </div>\n </div>\n {canManageSharedAgents && (\n <AlertDialog>\n <AlertDialogTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\">\n <IconTrash className=\"h-4 w-4\" />\n </Button>\n </AlertDialogTrigger>\n <AlertDialogContent>\n <AlertDialogHeader>\n <AlertDialogTitle>\n Remove this agent?\n </AlertDialogTitle>\n <AlertDialogDescription>\n “{agent.name}” will be removed from the workspace.\n Any jobs or chats that delegate to it will stop\n working.\n </AlertDialogDescription>\n </AlertDialogHeader>\n <AlertDialogFooter>\n <AlertDialogCancel>Cancel</AlertDialogCancel>\n <AlertDialogAction\n onClick={() => handleDelete(agent.resourceId)}\n >\n Remove\n </AlertDialogAction>\n </AlertDialogFooter>\n </AlertDialogContent>\n </AlertDialog>\n )}\n </div>\n ))}\n {workspaceAgents.length === 0 && customAgents.length === 0 && (\n <div className=\"rounded-xl border border-dashed px-4 py-6 text-sm text-muted-foreground\">\n No extra agents added yet.\n </div>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"rounded-xl border bg-muted/20 p-4\">\n <div className=\"text-sm font-medium text-foreground\">\n Add external agent\n </div>\n {canManageSharedAgents ? (\n <p className=\"mt-1 text-xs leading-relaxed text-muted-foreground\">\n Add another A2A-compatible app by saving its agent endpoint here.\n </p>\n ) : !orgLoading ? (\n <p className=\"mt-1 text-xs leading-relaxed text-muted-foreground\">\n Only workspace owners and admins can add shared agents.\n </p>\n ) : null}\n <form\n className={`mt-4 space-y-3 ${canManageSharedAgents ? \"\" : \"hidden\"}`}\n onSubmit={handleAdd}\n noValidate\n >\n <div className=\"space-y-1.5\">\n <Input\n ref={nameRef}\n value={name}\n onChange={(event) => {\n setName(event.target.value);\n setErrors((current) => ({ ...current, name: undefined }));\n }}\n placeholder=\"Name\"\n aria-invalid={Boolean(errors.name)}\n aria-describedby={\n errors.name ? \"external-agent-name-error\" : undefined\n }\n />\n {errors.name ? (\n <p\n id=\"external-agent-name-error\"\n className=\"text-xs font-medium text-destructive\"\n >\n {errors.name}\n </p>\n ) : null}\n </div>\n <div className=\"space-y-1.5\">\n <Input\n value={url}\n onChange={(event) => {\n setUrl(event.target.value);\n setErrors((current) => ({ ...current, url: undefined }));\n }}\n placeholder=\"https://app.example.com\"\n aria-invalid={Boolean(errors.url)}\n aria-describedby={\n errors.url ? \"external-agent-url-error\" : undefined\n }\n />\n {errors.url ? (\n <p\n id=\"external-agent-url-error\"\n className=\"text-xs font-medium text-destructive\"\n >\n {errors.url}\n </p>\n ) : null}\n </div>\n <Input\n value={description}\n onChange={(event) => setDescription(event.target.value)}\n placeholder=\"Description (optional)\"\n />\n {errors.form ? (\n <p className=\"text-xs font-medium text-destructive\">\n {errors.form}\n </p>\n ) : null}\n <Button\n type=\"submit\"\n className=\"w-full\"\n disabled={saving || !canManageSharedAgents}\n >\n {saving ? \"Saving...\" : \"Add agent\"}\n </Button>\n </form>\n </div>\n </div>\n </section>\n );\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/dispatch",
3
- "version": "0.24.2",
3
+ "version": "0.24.3",
4
4
  "description": "Dispatch — workspace control plane for agent-native apps. Vault, integrations, destinations, scheduled jobs, and cross-app delegation, shipped as a single drop-in package.",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -99,7 +99,7 @@
99
99
  "typescript-7": "npm:typescript@^7.0.2",
100
100
  "vite": "8.1.0",
101
101
  "vitest": "^4.1.5",
102
- "@agent-native/core": "0.153.0"
102
+ "@agent-native/core": "0.153.4"
103
103
  },
104
104
  "peerDependencies": {
105
105
  "@agent-native/core": ">=0.8.0",
@@ -1,4 +1,5 @@
1
1
  import { agentNativePath } from "@agent-native/core/client/api-path";
2
+ import { useOrgRole } from "@agent-native/core/client/org";
2
3
  import { IconExternalLink, IconTrash } from "@tabler/icons-react";
3
4
  import { useRef, useState, type FormEvent } from "react";
4
5
 
@@ -77,6 +78,11 @@ export function AgentsPanel({
77
78
  agents: ConnectedAgent[];
78
79
  onRefresh: () => void;
79
80
  }) {
81
+ const { org, isLoading: orgLoading, error: orgError } = useOrgRole();
82
+ const canManageSharedAgents =
83
+ !orgLoading &&
84
+ !orgError &&
85
+ (!org?.orgId || org.role === "owner" || org.role === "admin");
80
86
  const [name, setName] = useState("");
81
87
  const [url, setUrl] = useState("");
82
88
  const [description, setDescription] = useState("");
@@ -249,30 +255,35 @@ export function AgentsPanel({
249
255
  <span>{agent.scope || "shared"}</span>
250
256
  </div>
251
257
  </div>
252
- <AlertDialog>
253
- <AlertDialogTrigger asChild>
254
- <Button variant="ghost" size="icon">
255
- <IconTrash className="h-4 w-4" />
256
- </Button>
257
- </AlertDialogTrigger>
258
- <AlertDialogContent>
259
- <AlertDialogHeader>
260
- <AlertDialogTitle>Remove this agent?</AlertDialogTitle>
261
- <AlertDialogDescription>
262
- “{agent.name}” will be removed from the workspace. Any
263
- jobs or chats that delegate to it will stop working.
264
- </AlertDialogDescription>
265
- </AlertDialogHeader>
266
- <AlertDialogFooter>
267
- <AlertDialogCancel>Cancel</AlertDialogCancel>
268
- <AlertDialogAction
269
- onClick={() => handleDelete(agent.resourceId)}
270
- >
271
- Remove
272
- </AlertDialogAction>
273
- </AlertDialogFooter>
274
- </AlertDialogContent>
275
- </AlertDialog>
258
+ {canManageSharedAgents && (
259
+ <AlertDialog>
260
+ <AlertDialogTrigger asChild>
261
+ <Button variant="ghost" size="icon">
262
+ <IconTrash className="h-4 w-4" />
263
+ </Button>
264
+ </AlertDialogTrigger>
265
+ <AlertDialogContent>
266
+ <AlertDialogHeader>
267
+ <AlertDialogTitle>
268
+ Remove this agent?
269
+ </AlertDialogTitle>
270
+ <AlertDialogDescription>
271
+ “{agent.name}” will be removed from the workspace.
272
+ Any jobs or chats that delegate to it will stop
273
+ working.
274
+ </AlertDialogDescription>
275
+ </AlertDialogHeader>
276
+ <AlertDialogFooter>
277
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
278
+ <AlertDialogAction
279
+ onClick={() => handleDelete(agent.resourceId)}
280
+ >
281
+ Remove
282
+ </AlertDialogAction>
283
+ </AlertDialogFooter>
284
+ </AlertDialogContent>
285
+ </AlertDialog>
286
+ )}
276
287
  </div>
277
288
  ))}
278
289
  {workspaceAgents.length === 0 && customAgents.length === 0 && (
@@ -288,10 +299,20 @@ export function AgentsPanel({
288
299
  <div className="text-sm font-medium text-foreground">
289
300
  Add external agent
290
301
  </div>
291
- <p className="mt-1 text-xs leading-relaxed text-muted-foreground">
292
- Add another A2A-compatible app by saving its agent endpoint here.
293
- </p>
294
- <form className="mt-4 space-y-3" onSubmit={handleAdd} noValidate>
302
+ {canManageSharedAgents ? (
303
+ <p className="mt-1 text-xs leading-relaxed text-muted-foreground">
304
+ Add another A2A-compatible app by saving its agent endpoint here.
305
+ </p>
306
+ ) : !orgLoading ? (
307
+ <p className="mt-1 text-xs leading-relaxed text-muted-foreground">
308
+ Only workspace owners and admins can add shared agents.
309
+ </p>
310
+ ) : null}
311
+ <form
312
+ className={`mt-4 space-y-3 ${canManageSharedAgents ? "" : "hidden"}`}
313
+ onSubmit={handleAdd}
314
+ noValidate
315
+ >
295
316
  <div className="space-y-1.5">
296
317
  <Input
297
318
  ref={nameRef}
@@ -347,7 +368,11 @@ export function AgentsPanel({
347
368
  {errors.form}
348
369
  </p>
349
370
  ) : null}
350
- <Button type="submit" className="w-full" disabled={saving}>
371
+ <Button
372
+ type="submit"
373
+ className="w-full"
374
+ disabled={saving || !canManageSharedAgents}
375
+ >
351
376
  {saving ? "Saving..." : "Add agent"}
352
377
  </Button>
353
378
  </form>