From b69b8ceaffaf4c66e36a7115469eaa35d5621da5 Mon Sep 17 00:00:00 2001 From: Mikkel Georgsen Date: Wed, 1 Apr 2026 11:35:40 +0200 Subject: [PATCH] [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 --- ui/src/api/skillGroups.ts | 10 ++++------ ui/src/api/skillRegistry.ts | 16 ++++++++++++---- ui/src/pages/AgentDetail.tsx | 10 +++++----- ui/src/pages/SkillDetail.tsx | 31 +++++++++++++++---------------- 4 files changed, 36 insertions(+), 31 deletions(-) diff --git a/ui/src/api/skillGroups.ts b/ui/src/api/skillGroups.ts index 712e9eef..8c57ad05 100644 --- a/ui/src/api/skillGroups.ts +++ b/ui/src/api/skillGroups.ts @@ -1,4 +1,5 @@ import { api, ApiError } from "./client"; +import type { AgentSkillEntry } from "./skillRegistry"; export type SkillGroupRow = { id: string; @@ -65,18 +66,15 @@ export const skillGroupsApi = { listAgentGroups: (agentId: string) => api.get(`/skill-registry/agents/${agentId}/groups`), - assignGroup: (agentId: string, groupId: string, agentSkillsDir: string) => + assignGroup: (agentId: string, groupId: string) => api.post(`/skill-registry/agents/${agentId}/groups`, { groupId, - agentSkillsDir, }), - removeGroup: async (agentId: string, groupId: string, agentSkillsDir: string): Promise => { + removeGroup: async (agentId: string, groupId: string): Promise => { const res = await fetch(`/api/skill-registry/agents/${agentId}/groups/${groupId}`, { method: "DELETE", credentials: "include", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ agentSkillsDir }), }); if (!res.ok && res.status !== 204) { const errorBody = await res.json().catch(() => null); @@ -89,5 +87,5 @@ export const skillGroupsApi = { }, listAgentSkills: (agentId: string) => - api.get(`/skill-registry/agents/${agentId}/skills`), + api.get(`/skill-registry/agents/${agentId}/skills`), }; diff --git a/ui/src/api/skillRegistry.ts b/ui/src/api/skillRegistry.ts index ac29fc1b..77c043bf 100644 --- a/ui/src/api/skillRegistry.ts +++ b/ui/src/api/skillRegistry.ts @@ -1,5 +1,11 @@ import { api } from "./client"; +export type AgentSkillEntry = { + skillId: string; + source: "managed" | "native"; + installedAt: number; +}; + export type SkillListItem = { id: string; name: string; @@ -50,10 +56,12 @@ export const skillRegistryApi = { api.get(`${skillPath(skillId)}/versions`), fetch: () => api.post<{ fetched: number; errors: string[] }>("/skill-registry/fetch", {}), - install: (skillId: string, agentSkillsDir: string) => - api.post(`${skillPath(skillId)}/install`, { agentSkillsDir }), - rollback: (skillId: string, versionId: string, agentSkillsDir: string) => - api.post(`${skillPath(skillId)}/rollback`, { versionId, agentSkillsDir }), + install: (skillId: string, agentId: string) => + api.post(`${skillPath(skillId)}/install`, { agentId }), + uninstall: (skillId: string, agentId: string) => + api.delete(`${skillPath(skillId)}?agentId=${encodeURIComponent(agentId)}`), + rollback: (skillId: string, versionId: string, agentId: string) => + api.post(`${skillPath(skillId)}/rollback`, { versionId, agentId }), remove: (skillId: string) => api.delete(skillPath(skillId)), getRatings: (skillId: string) => diff --git a/ui/src/pages/AgentDetail.tsx b/ui/src/pages/AgentDetail.tsx index 943e3c08..8f0da859 100644 --- a/ui/src/pages/AgentDetail.tsx +++ b/ui/src/pages/AgentDetail.tsx @@ -2440,7 +2440,7 @@ function AgentSkillsTab({ // Group mutations const assignGroupMut = useMutation({ mutationFn: ({ groupId }: { groupId: string }) => - skillGroupsApi.assignGroup(agent.id, groupId, ""), + skillGroupsApi.assignGroup(agent.id, groupId), onSuccess: () => { void queryClient.invalidateQueries({ queryKey: queryKeys.skillGroups.agentGroups(agent.id) }); void queryClient.invalidateQueries({ queryKey: queryKeys.skillGroups.agentSkills(agent.id) }); @@ -2450,7 +2450,7 @@ function AgentSkillsTab({ const removeGroupMut = useMutation({ mutationFn: ({ groupId }: { groupId: string }) => - skillGroupsApi.removeGroup(agent.id, groupId, ""), + skillGroupsApi.removeGroup(agent.id, groupId), onSuccess: () => { void queryClient.invalidateQueries({ queryKey: queryKeys.skillGroups.agentGroups(agent.id) }); void queryClient.invalidateQueries({ queryKey: queryKeys.skillGroups.agentSkills(agent.id) }); @@ -2735,9 +2735,9 @@ function AgentSkillsTab({ ) : (
    - {(agentEffectiveSkillsQuery.data ?? []).map((skillId) => ( -
  • - {skillId} + {(agentEffectiveSkillsQuery.data ?? []).map((entry) => ( +
  • + {entry.skillId}
  • ))}
diff --git a/ui/src/pages/SkillDetail.tsx b/ui/src/pages/SkillDetail.tsx index 9d000cf6..957fa455 100644 --- a/ui/src/pages/SkillDetail.tsx +++ b/ui/src/pages/SkillDetail.tsx @@ -95,7 +95,7 @@ export function SkillDetail() { const [installDialog, setInstallDialog] = useState<{ skillId: string; isUpdate: boolean; - agentSkillsDir?: string; + agentId?: string; } | null>(null); // Uninstall confirmation dialog state @@ -149,8 +149,8 @@ export function SkillDetail() { }; const installMutation = useMutation({ - mutationFn: ({ agentSkillsDir }: { agentSkillsDir: string }) => - skillRegistryApi.install(skillId, agentSkillsDir), + mutationFn: ({ agentId }: { agentId: string }) => + skillRegistryApi.install(skillId, agentId), onSuccess: () => { invalidateSkill(); setInstallDialog(null); @@ -162,8 +162,8 @@ export function SkillDetail() { }); const updateMutation = useMutation({ - mutationFn: ({ agentSkillsDir }: { agentSkillsDir: string }) => - skillRegistryApi.install(skillId, agentSkillsDir), + mutationFn: ({ agentId }: { agentId: string }) => + skillRegistryApi.install(skillId, agentId), onSuccess: () => { invalidateSkill(); setInstallDialog(null); @@ -175,8 +175,8 @@ export function SkillDetail() { }); const rollbackMutation = useMutation({ - mutationFn: ({ versionId, agentSkillsDir }: { versionId: string; agentSkillsDir: string }) => - skillRegistryApi.rollback(skillId, versionId, agentSkillsDir), + mutationFn: ({ versionId, agentId }: { versionId: string; agentId: string }) => + skillRegistryApi.rollback(skillId, versionId, agentId), onSuccess: () => { invalidateSkill(); pushToast({ title: "Rolled back to previous version", tone: "success" }); @@ -596,16 +596,15 @@ export function SkillDetail() {

- Agent skills directory is required to install. Enter the path to the agent's - skills directory. + Enter the agent ID to install this skill.

- setInstallDialog((d) => d ? { ...d, agentSkillsDir: e.target.value } : null) + setInstallDialog((d) => d ? { ...d, agentId: e.target.value } : null) } />
@@ -614,13 +613,13 @@ export function SkillDetail() { Cancel