[nexus] feat(19-03): update API client to use agentId instead of agentSkillsDir
- Add AgentSkillEntry type with skillId, source, installedAt fields - install() now sends agentId in body not agentSkillsDir - uninstall() new function that sends agentId as query param - rollback() now sends agentId in body not agentSkillsDir - skillGroups.assignGroup/removeGroup no longer accept agentSkillsDir param - listAgentSkills now returns AgentSkillEntry[] not string[] - Fix AgentDetail.tsx callers and entry rendering for new AgentSkillEntry type - Fix SkillDetail.tsx callers to use agentId param
This commit is contained in:
parent
db83eb2a00
commit
305ea411da
4 changed files with 36 additions and 31 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
import { api, ApiError } from "./client";
|
import { api, ApiError } from "./client";
|
||||||
|
import type { AgentSkillEntry } from "./skillRegistry";
|
||||||
|
|
||||||
export type SkillGroupRow = {
|
export type SkillGroupRow = {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -65,18 +66,15 @@ export const skillGroupsApi = {
|
||||||
listAgentGroups: (agentId: string) =>
|
listAgentGroups: (agentId: string) =>
|
||||||
api.get<SkillGroupRow[]>(`/skill-registry/agents/${agentId}/groups`),
|
api.get<SkillGroupRow[]>(`/skill-registry/agents/${agentId}/groups`),
|
||||||
|
|
||||||
assignGroup: (agentId: string, groupId: string, agentSkillsDir: string) =>
|
assignGroup: (agentId: string, groupId: string) =>
|
||||||
api.post<AssignResult>(`/skill-registry/agents/${agentId}/groups`, {
|
api.post<AssignResult>(`/skill-registry/agents/${agentId}/groups`, {
|
||||||
groupId,
|
groupId,
|
||||||
agentSkillsDir,
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
removeGroup: async (agentId: string, groupId: string, agentSkillsDir: string): Promise<void> => {
|
removeGroup: async (agentId: string, groupId: string): Promise<void> => {
|
||||||
const res = await fetch(`/api/skill-registry/agents/${agentId}/groups/${groupId}`, {
|
const res = await fetch(`/api/skill-registry/agents/${agentId}/groups/${groupId}`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
headers: { "Content-Type": "application/json" },
|
|
||||||
body: JSON.stringify({ agentSkillsDir }),
|
|
||||||
});
|
});
|
||||||
if (!res.ok && res.status !== 204) {
|
if (!res.ok && res.status !== 204) {
|
||||||
const errorBody = await res.json().catch(() => null);
|
const errorBody = await res.json().catch(() => null);
|
||||||
|
|
@ -89,5 +87,5 @@ export const skillGroupsApi = {
|
||||||
},
|
},
|
||||||
|
|
||||||
listAgentSkills: (agentId: string) =>
|
listAgentSkills: (agentId: string) =>
|
||||||
api.get<string[]>(`/skill-registry/agents/${agentId}/skills`),
|
api.get<AgentSkillEntry[]>(`/skill-registry/agents/${agentId}/skills`),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,11 @@
|
||||||
import { api } from "./client";
|
import { api } from "./client";
|
||||||
|
|
||||||
|
export type AgentSkillEntry = {
|
||||||
|
skillId: string;
|
||||||
|
source: "managed" | "native";
|
||||||
|
installedAt: number;
|
||||||
|
};
|
||||||
|
|
||||||
export type SkillListItem = {
|
export type SkillListItem = {
|
||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
@ -50,10 +56,12 @@ export const skillRegistryApi = {
|
||||||
api.get<SkillVersion[]>(`${skillPath(skillId)}/versions`),
|
api.get<SkillVersion[]>(`${skillPath(skillId)}/versions`),
|
||||||
fetch: () =>
|
fetch: () =>
|
||||||
api.post<{ fetched: number; errors: string[] }>("/skill-registry/fetch", {}),
|
api.post<{ fetched: number; errors: string[] }>("/skill-registry/fetch", {}),
|
||||||
install: (skillId: string, agentSkillsDir: string) =>
|
install: (skillId: string, agentId: string) =>
|
||||||
api.post(`${skillPath(skillId)}/install`, { agentSkillsDir }),
|
api.post(`${skillPath(skillId)}/install`, { agentId }),
|
||||||
rollback: (skillId: string, versionId: string, agentSkillsDir: string) =>
|
uninstall: (skillId: string, agentId: string) =>
|
||||||
api.post(`${skillPath(skillId)}/rollback`, { versionId, agentSkillsDir }),
|
api.delete(`${skillPath(skillId)}?agentId=${encodeURIComponent(agentId)}`),
|
||||||
|
rollback: (skillId: string, versionId: string, agentId: string) =>
|
||||||
|
api.post(`${skillPath(skillId)}/rollback`, { versionId, agentId }),
|
||||||
remove: (skillId: string) =>
|
remove: (skillId: string) =>
|
||||||
api.delete(skillPath(skillId)),
|
api.delete(skillPath(skillId)),
|
||||||
getRatings: (skillId: string) =>
|
getRatings: (skillId: string) =>
|
||||||
|
|
|
||||||
|
|
@ -2440,7 +2440,7 @@ function AgentSkillsTab({
|
||||||
// Group mutations
|
// Group mutations
|
||||||
const assignGroupMut = useMutation({
|
const assignGroupMut = useMutation({
|
||||||
mutationFn: ({ groupId }: { groupId: string }) =>
|
mutationFn: ({ groupId }: { groupId: string }) =>
|
||||||
skillGroupsApi.assignGroup(agent.id, groupId, ""),
|
skillGroupsApi.assignGroup(agent.id, groupId),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
void queryClient.invalidateQueries({ queryKey: queryKeys.skillGroups.agentGroups(agent.id) });
|
void queryClient.invalidateQueries({ queryKey: queryKeys.skillGroups.agentGroups(agent.id) });
|
||||||
void queryClient.invalidateQueries({ queryKey: queryKeys.skillGroups.agentSkills(agent.id) });
|
void queryClient.invalidateQueries({ queryKey: queryKeys.skillGroups.agentSkills(agent.id) });
|
||||||
|
|
@ -2450,7 +2450,7 @@ function AgentSkillsTab({
|
||||||
|
|
||||||
const removeGroupMut = useMutation({
|
const removeGroupMut = useMutation({
|
||||||
mutationFn: ({ groupId }: { groupId: string }) =>
|
mutationFn: ({ groupId }: { groupId: string }) =>
|
||||||
skillGroupsApi.removeGroup(agent.id, groupId, ""),
|
skillGroupsApi.removeGroup(agent.id, groupId),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
void queryClient.invalidateQueries({ queryKey: queryKeys.skillGroups.agentGroups(agent.id) });
|
void queryClient.invalidateQueries({ queryKey: queryKeys.skillGroups.agentGroups(agent.id) });
|
||||||
void queryClient.invalidateQueries({ queryKey: queryKeys.skillGroups.agentSkills(agent.id) });
|
void queryClient.invalidateQueries({ queryKey: queryKeys.skillGroups.agentSkills(agent.id) });
|
||||||
|
|
@ -2735,9 +2735,9 @@ function AgentSkillsTab({
|
||||||
) : (
|
) : (
|
||||||
<ScrollArea className="max-h-[300px] pt-2">
|
<ScrollArea className="max-h-[300px] pt-2">
|
||||||
<ul className="space-y-1">
|
<ul className="space-y-1">
|
||||||
{(agentEffectiveSkillsQuery.data ?? []).map((skillId) => (
|
{(agentEffectiveSkillsQuery.data ?? []).map((entry) => (
|
||||||
<li key={skillId} className="text-sm text-muted-foreground font-mono">
|
<li key={entry.skillId} className="text-sm text-muted-foreground font-mono">
|
||||||
{skillId}
|
{entry.skillId}
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,7 @@ export function SkillDetail() {
|
||||||
const [installDialog, setInstallDialog] = useState<{
|
const [installDialog, setInstallDialog] = useState<{
|
||||||
skillId: string;
|
skillId: string;
|
||||||
isUpdate: boolean;
|
isUpdate: boolean;
|
||||||
agentSkillsDir?: string;
|
agentId?: string;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
// Uninstall confirmation dialog state
|
// Uninstall confirmation dialog state
|
||||||
|
|
@ -149,8 +149,8 @@ export function SkillDetail() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const installMutation = useMutation({
|
const installMutation = useMutation({
|
||||||
mutationFn: ({ agentSkillsDir }: { agentSkillsDir: string }) =>
|
mutationFn: ({ agentId }: { agentId: string }) =>
|
||||||
skillRegistryApi.install(skillId, agentSkillsDir),
|
skillRegistryApi.install(skillId, agentId),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
invalidateSkill();
|
invalidateSkill();
|
||||||
setInstallDialog(null);
|
setInstallDialog(null);
|
||||||
|
|
@ -162,8 +162,8 @@ export function SkillDetail() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateMutation = useMutation({
|
const updateMutation = useMutation({
|
||||||
mutationFn: ({ agentSkillsDir }: { agentSkillsDir: string }) =>
|
mutationFn: ({ agentId }: { agentId: string }) =>
|
||||||
skillRegistryApi.install(skillId, agentSkillsDir),
|
skillRegistryApi.install(skillId, agentId),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
invalidateSkill();
|
invalidateSkill();
|
||||||
setInstallDialog(null);
|
setInstallDialog(null);
|
||||||
|
|
@ -175,8 +175,8 @@ export function SkillDetail() {
|
||||||
});
|
});
|
||||||
|
|
||||||
const rollbackMutation = useMutation({
|
const rollbackMutation = useMutation({
|
||||||
mutationFn: ({ versionId, agentSkillsDir }: { versionId: string; agentSkillsDir: string }) =>
|
mutationFn: ({ versionId, agentId }: { versionId: string; agentId: string }) =>
|
||||||
skillRegistryApi.rollback(skillId, versionId, agentSkillsDir),
|
skillRegistryApi.rollback(skillId, versionId, agentId),
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
invalidateSkill();
|
invalidateSkill();
|
||||||
pushToast({ title: "Rolled back to previous version", tone: "success" });
|
pushToast({ title: "Rolled back to previous version", tone: "success" });
|
||||||
|
|
@ -596,16 +596,15 @@ export function SkillDetail() {
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<div className="py-2">
|
<div className="py-2">
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
Agent skills directory is required to install. Enter the path to the agent's
|
Enter the agent ID to install this skill.
|
||||||
skills directory.
|
|
||||||
</p>
|
</p>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="mt-2 w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-ring"
|
className="mt-2 w-full rounded-md border border-border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-ring"
|
||||||
placeholder="/path/to/agent/skills"
|
placeholder="Agent ID"
|
||||||
value={installDialog?.agentSkillsDir ?? ""}
|
value={installDialog?.agentId ?? ""}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setInstallDialog((d) => d ? { ...d, agentSkillsDir: e.target.value } : null)
|
setInstallDialog((d) => d ? { ...d, agentId: e.target.value } : null)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -614,13 +613,13 @@ export function SkillDetail() {
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
disabled={!installDialog?.agentSkillsDir || isMutating}
|
disabled={!installDialog?.agentId || isMutating}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!installDialog?.agentSkillsDir) return;
|
if (!installDialog?.agentId) return;
|
||||||
if (installDialog.isUpdate) {
|
if (installDialog.isUpdate) {
|
||||||
updateMutation.mutate({ agentSkillsDir: installDialog.agentSkillsDir });
|
updateMutation.mutate({ agentId: installDialog.agentId });
|
||||||
} else {
|
} else {
|
||||||
installMutation.mutate({ agentSkillsDir: installDialog.agentSkillsDir });
|
installMutation.mutate({ agentId: installDialog.agentId });
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue