diff --git a/agentscope-examples/agents/agentscope-builder/src/main/java/io/agentscope/builder/runtime/marketplace/NacosBuilderMarketplace.java b/agentscope-examples/agents/agentscope-builder/src/main/java/io/agentscope/builder/runtime/marketplace/NacosBuilderMarketplace.java index 851dfa7f9b..af3507c9ce 100644 --- a/agentscope-examples/agents/agentscope-builder/src/main/java/io/agentscope/builder/runtime/marketplace/NacosBuilderMarketplace.java +++ b/agentscope-examples/agents/agentscope-builder/src/main/java/io/agentscope/builder/runtime/marketplace/NacosBuilderMarketplace.java @@ -17,6 +17,7 @@ import com.alibaba.nacos.api.PropertyKeyConst; import com.alibaba.nacos.api.ai.model.skills.Skill; +import com.alibaba.nacos.api.ai.model.skills.SkillMeta; import com.alibaba.nacos.api.ai.model.skills.SkillResource; import com.alibaba.nacos.api.ai.model.skills.SkillSummary; import com.alibaba.nacos.api.exception.NacosException; @@ -34,8 +35,9 @@ /** * Nacos-backed marketplace. Uses the maintainer client (not the regular AiService client, - * which only exposes downloads) to drive the paged {@code listSkills} API and pull SKILL.md - * via {@code getSkillVersionDetail(..., "LATEST")}. + * which only exposes downloads) to drive the paged {@code listSkills} API. Skill content is + * fetched by resolving the real version from the skill metadata's {@code latest} label, then + * calling {@code getSkillVersionDetail(..., resolvedVersion)}. * *
Pagination: builder is a multi-tenant platform — but we still expect skill counts on the order of 100s per user, not millions. We page through * the upstream result in batches of {@link #PAGE_SIZE} until the server reports we have all @@ -47,7 +49,8 @@ public class NacosBuilderMarketplace implements BuilderMarketplace { private static final int PAGE_SIZE = 100; private static final int MAX_PAGES = 50; - private static final String LATEST_VERSION = "LATEST"; + private static final String LATEST_LABEL = "latest"; + private static final String ONLINE_STATUS = "online"; private final String id; private final String serverAddr; @@ -156,8 +159,13 @@ public MarketSkillContent fetch(String name) { return null; } try { + String skillName = name.trim(); + SkillMaintainerService skillService = service.skill(); + SkillMeta skillMeta = skillService.getSkillMeta(namespaceId, skillName); + String resolvedVersion = resolveLatestSkillVersion(namespaceId, skillName, skillMeta); + Skill skill = - service.skill().getSkillVersionDetail(namespaceId, name.trim(), LATEST_VERSION); + skillService.getSkillVersionDetail(namespaceId, skillName, resolvedVersion); if (skill == null || skill.getSkillMd() == null || skill.getSkillMd().isEmpty()) { return null; } @@ -202,4 +210,62 @@ public void close() { private static String blankToNull(String v) { return (v == null || v.isBlank()) ? null : v.trim(); } + + private static String resolveLatestSkillVersion( + String namespaceId, String skillName, SkillMeta skillMeta) { + String version = + skillMeta != null && skillMeta.getLabels() != null + ? skillMeta.getLabels().get(LATEST_LABEL) + : null; + if (version == null || version.isBlank()) { + throw new IllegalStateException( + "Nacos skill metadata is missing a '" + + LATEST_LABEL + + "' label for " + + namespaceId + + "/" + + skillName + + "; cannot resolve latest version"); + } + + if (skillMeta.getVersions() == null || skillMeta.getVersions().isEmpty()) { + throw new IllegalStateException( + "Nacos skill latest label points to unknown version '" + + version + + "' for " + + namespaceId + + "/" + + skillName + + "; metadata versions are empty"); + } + + for (SkillMeta.SkillVersionSummary summary : skillMeta.getVersions()) { + if (summary == null || !version.equals(summary.getVersion())) { + continue; + } + String status = summary.getStatus(); + if (!ONLINE_STATUS.equalsIgnoreCase(status)) { + throw new IllegalStateException( + "Nacos skill latest version '" + + version + + "' for " + + namespaceId + + "/" + + skillName + + " is not online" + + " (status=" + + status + + ")"); + } + return version; + } + + throw new IllegalStateException( + "Nacos skill latest label points to unknown version '" + + version + + "' for " + + namespaceId + + "/" + + skillName); + } }