Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package io.agentscope.core.skill;

import io.agentscope.core.skill.util.SkillFileSystemHelper;
import io.agentscope.core.state.StateModule;
import io.agentscope.core.tool.AgentTool;
import io.agentscope.core.tool.ExtendedModel;
Expand Down Expand Up @@ -670,38 +671,18 @@ public Path getUploadDir() {
* @throws RuntimeException if failed to create the directory
*/
private Path ensureWorkDirExists() {
Path workDir;

if (this.workDir == null) {
// Create temporary directory
try {
workDir = Files.createTempDirectory("agentscope-code-execution-");

// Register shutdown hook to clean up temporary directory
Runtime.getRuntime()
.addShutdownHook(
new Thread(
() -> {
try {
deleteTempDirectory(workDir);
logger.info(
"Cleaned up temporary working directory:"
+ " {}",
workDir);
} catch (IOException e) {
logger.warn(
"Failed to clean up temporary directory:"
+ " {}",
e.getMessage());
}
}));
this.workDir = Files.createTempDirectory("agentscope-code-execution-");

SkillFileSystemHelper.registerTempDirectoryCleanup(workDir);

logger.info("Created temporary working directory: {}", workDir);
Comment on lines +677 to 681
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

workDir is referenced but no longer declared in this method (e.g., in registerTempDirectoryCleanup(workDir) and the log statement). This will not compile; use this.workDir (or introduce a local Path workDir = this.workDir) consistently after creating the temp directory.

Copilot uses AI. Check for mistakes.
} catch (IOException e) {
throw new RuntimeException("Failed to create temporary working directory", e);
}
} else {
workDir = this.workDir;
// Create directory if it doesn't exist
if (!Files.exists(workDir)) {
try {
Expand All @@ -713,7 +694,7 @@ private Path ensureWorkDirExists() {
}
}

return workDir;
return this.workDir;
}

/**
Expand All @@ -722,54 +703,21 @@ private Path ensureWorkDirExists() {
* @return The upload directory path
*/
private Path ensureUploadDirExists() {
Path targetDir = uploadDir;
if (targetDir == null) {
if (uploadDir == null) {
Path resolvedWorkDir = ensureWorkDirExists();
targetDir = resolvedWorkDir.resolve("skills");
uploadDir = resolvedWorkDir.resolve("skills");
}

if (!Files.exists(targetDir)) {
if (!Files.exists(uploadDir)) {
try {
Files.createDirectories(targetDir);
logger.info("Created upload directory: {}", targetDir);
Files.createDirectories(uploadDir);
logger.info("Created upload directory: {}", uploadDir);
} catch (IOException e) {
throw new RuntimeException("Failed to create upload directory", e);
}
}

if (uploadDir == null) {
uploadDir = targetDir;
}

return targetDir;
}

/**
* Deletes the temporary working directory if it was created.
*
* <p>
* This method only deletes directories that were created as temporary
* directories
* by this SkillBox instance. User-specified directories are never deleted.
*
* @throws IOException if deletion fails
*/
private void deleteTempDirectory(Path temporaryWorkDir) throws IOException {
if (temporaryWorkDir != null && Files.exists(temporaryWorkDir)) {
Files.walk(temporaryWorkDir)
.sorted(
(a, b) ->
-a.compareTo(
b)) // Reverse order to delete files before directories
.forEach(
path -> {
try {
Files.delete(path);
} catch (IOException e) {
logger.warn("Failed to delete: {}", path);
}
});
}
return uploadDir;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ public AgentSkillRepositoryInfo getRepositoryInfo() {

@Override
public String getSource() {
return source != null ? source : "filesystem_" + buildDefaultSourceSuffix();
return source != null ? source : "filesystem:" + buildDefaultSourceSuffix();
}

private String buildDefaultSourceSuffix() {
Expand All @@ -170,7 +170,7 @@ private String buildDefaultSourceSuffix() {
return fileName.toString();
}

return parent.getFileName() + "/" + fileName;
return parent.getFileName() + "_" + fileName;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,29 @@ public URL getResource(String name) {
}
}

// ==================== getSource Tests ====================

@Test
@DisplayName("Should return default source with format: classpath:path")
void testGetSource_DefaultSource() throws IOException {
repository = new ClasspathSkillRepository("test-skills");
assertEquals("classpath:test-skills", repository.getSource());
}

@Test
@DisplayName("Should return custom source when provided")
void testGetSource_CustomSource() throws IOException {
repository = new ClasspathSkillRepository("test-skills", "my-custom-source");
assertEquals("my-custom-source", repository.getSource());
}

@Test
@DisplayName("Should handle trailing slash in path")
void testGetSource_TrailingSlash() throws IOException {
repository = new ClasspathSkillRepository("test-skills/");
assertEquals("classpath:test-skills", repository.getSource());
}

// ==================== Error Handling Tests ====================

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,14 +131,52 @@ void testConstructor_RelativePath() throws IOException {
// ==================== getSource Tests ====================

@Test
@DisplayName("Should return correct source format")
void testGetSource() {
String source = repository.getSource();
assertNotNull(source);
assertTrue(source.startsWith("filesystem_"));
String expectedSuffix =
skillsBaseDir.getParent().getFileName() + "/" + skillsBaseDir.getFileName();
assertEquals("filesystem_" + expectedSuffix, source);
@DisplayName("Should return default source with format: filesystem:parent_child")
void testGetSource_DefaultSource() {
assertTrue(repository.getSource().matches("filesystem:[^_]+_skills"));
Copy link

Copilot AI Feb 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex filesystem:[^_]+_skills assumes the parent directory name contains no underscores, but buildDefaultSourceSuffix() does not enforce that. This can make the test flaky depending on the temp directory name. Consider asserting against the exact expected suffix derived from skillsBaseDir.getParent().getFileName() and skillsBaseDir.getFileName() (or relax the regex to avoid assumptions about underscores).

Suggested change
assertTrue(repository.getSource().matches("filesystem:[^_]+_skills"));
String parentName = skillsBaseDir.getParent().getFileName().toString();
String childName = skillsBaseDir.getFileName().toString();
String expectedSource = "filesystem:" + parentName + "_" + childName;
assertEquals(expectedSource, repository.getSource());

Copilot uses AI. Check for mistakes.
}

@Test
@DisplayName("Should return custom source when provided")
void testGetSource_CustomSource() {
FileSystemSkillRepository repo =
new FileSystemSkillRepository(skillsBaseDir, true, "custom-source");
assertEquals("custom-source", repo.getSource());
}

@Test
@DisplayName("Should use default source when null")
void testGetSource_Null() {
FileSystemSkillRepository repo = new FileSystemSkillRepository(skillsBaseDir, true, null);
assertTrue(repo.getSource().startsWith("filesystem:"));
}

// ==================== buildDefaultSourceSuffix Tests ====================

@Test
@DisplayName("Should build source: parent_child")
void testBuildSourceSuffix_TwoLevels() throws IOException {
Path dir = tempDir.resolve("parent").resolve("child");
Files.createDirectories(dir);
assertEquals("filesystem:parent_child", new FileSystemSkillRepository(dir).getSource());
}

@Test
@DisplayName("Should use last two levels for deep paths")
void testBuildSourceSuffix_DeepPath() throws IOException {
Path dir = tempDir.resolve("a/b/c/d");
Files.createDirectories(dir);
assertEquals("filesystem:c_d", new FileSystemSkillRepository(dir).getSource());
}

@Test
@DisplayName("Should preserve special chars in path")
void testBuildSourceSuffix_SpecialChars() throws IOException {
Path dir = tempDir.resolve("my-project").resolve("skills_v1.0");
Files.createDirectories(dir);
assertEquals(
"filesystem:my-project_skills_v1.0",
new FileSystemSkillRepository(dir).getSource());
}

// ==================== getRepositoryInfo Tests ====================
Expand Down
Loading