diff --git a/agentscope-core/src/main/java/io/agentscope/core/skill/repository/AgentSkillRepository.java b/agentscope-core/src/main/java/io/agentscope/core/skill/repository/AgentSkillRepository.java index f04134e890..2261a9e7ce 100644 --- a/agentscope-core/src/main/java/io/agentscope/core/skill/repository/AgentSkillRepository.java +++ b/agentscope-core/src/main/java/io/agentscope/core/skill/repository/AgentSkillRepository.java @@ -120,6 +120,57 @@ public interface AgentSkillRepository extends AutoCloseable { */ boolean isWriteable(); + /** + * Reads a single raw file under a skill directory. + * + *

For filesystem-backed repositories, this reads a file from the skill's + * directory on disk. For database-backed repositories, this may retrieve + * a skill resource stored as a BLOB or text column. + * + *

The default implementation returns {@code null} — callers should check + * the return value and handle unsupported operations gracefully. + * + * @param skillName The skill name (never null) + * @param relPath The relative path within the skill directory (e.g. "SKILL.md", + * "references/api.md") + * @return The file content, or {@code null} if the file does not exist or the + * operation is not supported by this repository implementation + */ + default String readSkillFile(String skillName, String relPath) { + return null; + } + + /** + * Writes a single raw file under a skill directory. + * + *

The default implementation returns {@code false} — callers should check + * the return value and handle unsupported operations gracefully. + * + * @param skillName The skill name + * @param relPath The relative path within the skill directory + * @param content The file content to write + * @return {@code true} if the write succeeded, {@code false} otherwise + */ + default boolean writeSkillFile(String skillName, String relPath, String content) { + return false; + } + + /** + * Deletes a single raw file under a skill directory. + * + *

Idempotent: implementations should return {@code true} for missing files. + * The default implementation returns {@code false} — callers should check + * the return value and handle unsupported operations gracefully. + * + * @param skillName The skill name + * @param relPath The relative path within the skill directory + * @return {@code true} if the delete succeeded (or file was already missing), + * {@code false} if the operation is not supported + */ + default boolean deleteSkillFile(String skillName, String relPath) { + return false; + } + /** * Cleans up any resources used by this repository. * diff --git a/agentscope-harness/src/main/java/io/agentscope/harness/agent/tool/SkillManageTool.java b/agentscope-harness/src/main/java/io/agentscope/harness/agent/tool/SkillManageTool.java index 354459a754..1e5fdc3cfa 100644 --- a/agentscope-harness/src/main/java/io/agentscope/harness/agent/tool/SkillManageTool.java +++ b/agentscope-harness/src/main/java/io/agentscope/harness/agent/tool/SkillManageTool.java @@ -21,7 +21,7 @@ import io.agentscope.core.skill.util.SkillUtil; import io.agentscope.core.tool.AgentTool; import io.agentscope.core.tool.ToolCallParam; -import io.agentscope.harness.agent.skill.WorkspaceSkillRepository; +import io.agentscope.core.skill.repository.AgentSkillRepository; import io.agentscope.harness.agent.skill.curator.SkillAuditLog; import io.agentscope.harness.agent.skill.curator.SkillSecurityScanner; import io.agentscope.harness.agent.skill.curator.SkillUsageRecord; @@ -73,10 +73,10 @@ public class SkillManageTool implements AgentTool { Set.of("references", "templates", "scripts", "assets"); /** Repository pointing at the live skills root (e.g. {@code skills/}). */ - private final WorkspaceSkillRepository mainRepo; + private final AgentSkillRepository mainRepo; /** Repository pointing at the draft staging dir (e.g. {@code skills/_drafts/}). */ - private final WorkspaceSkillRepository draftsRepo; + private final AgentSkillRepository draftsRepo; /** Optional telemetry sidecar; null disables provenance + counter writes. */ private final SkillUsageStore usageStore; @@ -87,23 +87,23 @@ public class SkillManageTool implements AgentTool { private final SkillManageConfig config; public SkillManageTool( - WorkspaceSkillRepository mainRepo, - WorkspaceSkillRepository draftsRepo, + AgentSkillRepository mainRepo, + AgentSkillRepository draftsRepo, SkillManageConfig config) { this(mainRepo, draftsRepo, config, null, null); } public SkillManageTool( - WorkspaceSkillRepository mainRepo, - WorkspaceSkillRepository draftsRepo, + AgentSkillRepository mainRepo, + AgentSkillRepository draftsRepo, SkillManageConfig config, SkillUsageStore usageStore) { this(mainRepo, draftsRepo, config, usageStore, null); } public SkillManageTool( - WorkspaceSkillRepository mainRepo, - WorkspaceSkillRepository draftsRepo, + AgentSkillRepository mainRepo, + AgentSkillRepository draftsRepo, SkillManageConfig config, SkillUsageStore usageStore, SkillAuditLog auditLog) { @@ -330,7 +330,7 @@ private ToolResultBlock doCreate(String name, String content, String sessionId) "Description exceeds " + MAX_DESCRIPTION_LENGTH + " chars."); } - WorkspaceSkillRepository target = config.autoPromote() ? mainRepo : draftsRepo; + AgentSkillRepository target = config.autoPromote() ? mainRepo : draftsRepo; boolean ok = target.save(List.of(skill), false); if (!ok) { return ToolResultBlock.error( @@ -393,7 +393,7 @@ private ToolResultBlock doEdit(String name, String content) { if (contentErr != null) { return ToolResultBlock.error(contentErr); } - WorkspaceSkillRepository target = locate(name); + AgentSkillRepository target = locate(name); if (target == null) { return ToolResultBlock.error("Skill '" + name + "' not found."); } @@ -441,7 +441,7 @@ private ToolResultBlock doPatch( return ToolResultBlock.error( "Missing 'new_string' for patch (use empty string to delete matched text)."); } - WorkspaceSkillRepository target = locate(name); + AgentSkillRepository target = locate(name); if (target == null) { return ToolResultBlock.error("Skill '" + name + "' not found."); } @@ -562,7 +562,7 @@ private ToolResultBlock doWriteFile(String name, String filePath, String fileCon return ToolResultBlock.error( "file_content exceeds " + MAX_SKILL_FILE_BYTES + " bytes."); } - WorkspaceSkillRepository target = locate(name); + AgentSkillRepository target = locate(name); if (target == null) { return ToolResultBlock.error("Skill '" + name + "' not found."); } @@ -600,7 +600,7 @@ private ToolResultBlock doRemoveFile(String name, String filePath) { if (filePathErr != null) { return ToolResultBlock.error(filePathErr); } - WorkspaceSkillRepository target = locate(name); + AgentSkillRepository target = locate(name); if (target == null) { return ToolResultBlock.error("Skill '" + name + "' not found."); } @@ -613,7 +613,7 @@ private ToolResultBlock doRemoveFile(String name, String filePath) { } private ToolResultBlock doDelete(String name, String absorbedInto) { - WorkspaceSkillRepository target = locate(name); + AgentSkillRepository target = locate(name); if (target == null) { return ToolResultBlock.error("Skill '" + name + "' not found."); } @@ -671,7 +671,7 @@ private void bumpPatchSilent(String name) { } /** Locate the repository that owns a skill by name; drafts win on collision. */ - private WorkspaceSkillRepository locate(String name) { + private AgentSkillRepository locate(String name) { if (draftsRepo.skillExists(name)) { return draftsRepo; }