mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-06-10 03:07:32 +08:00
feat(agent): wire conversation workspace into skill code execution
Pass the ReAct agent context workspace directory through SkillBoxFactory so SkillBox's code execution runs against the conversation workspace instead of the process default. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -409,7 +409,7 @@ public abstract class ReActAgentComponent extends NodeComponent {
|
||||
SkillTrackingHook skillTrackingHook = null;
|
||||
SkillBox skillBox = null;
|
||||
if (enableSkills()) {
|
||||
SkillLoadResult skillLoadResult = SkillBoxFactory.build(toolkit, cfg, skills());
|
||||
SkillLoadResult skillLoadResult = SkillBoxFactory.build(toolkit, cfg, skills(), ctx.getWorkspaceDir());
|
||||
skillBox = skillLoadResult.skillBox();
|
||||
skillTrackingHook = new SkillTrackingHook(skillLoadResult.skillIdToName());
|
||||
allHooks.add(skillTrackingHook);
|
||||
|
||||
@@ -30,10 +30,18 @@ public final class SkillBoxFactory {
|
||||
}
|
||||
|
||||
public static SkillLoadResult build(Toolkit toolkit, AgentConfig agentConfig, List<String> allowedSkills) {
|
||||
return build(toolkit, agentConfig, allowedSkills, null);
|
||||
}
|
||||
|
||||
public static SkillLoadResult build(
|
||||
Toolkit toolkit,
|
||||
AgentConfig agentConfig,
|
||||
List<String> allowedSkills,
|
||||
Path workspaceDir) {
|
||||
SkillsConfig skillsConfig = agentConfig.getSkills();
|
||||
Path root = Path.of(skillsConfig.getPath()).normalize();
|
||||
if (!Files.isDirectory(root)) {
|
||||
return handleMissingRoot(root, skillsConfig, toolkit);
|
||||
return handleMissingRoot(root, skillsConfig, toolkit, workspaceDir);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -41,7 +49,7 @@ public final class SkillBoxFactory {
|
||||
List<AgentSkill> allSkills = repository.getAllSkills();
|
||||
List<AgentSkill> selected = selectSkills(allSkills, allowedSkills, skillsConfig);
|
||||
SkillToolManifest manifest = new SkillToolManifest(root, skillsConfig);
|
||||
SkillBox skillBox = new SkillBox(toolkit);
|
||||
SkillBox skillBox = createSkillBox(toolkit, workspaceDir);
|
||||
Map<String, String> skillIdToName = new LinkedHashMap<>();
|
||||
List<String> skillNames = new ArrayList<>();
|
||||
|
||||
@@ -68,17 +76,31 @@ public final class SkillBoxFactory {
|
||||
throw new AgentConfigException("Failed to load skills from: " + root, e);
|
||||
}
|
||||
LOG.warn("Failed to load skills from {}: {}", root, e.getMessage());
|
||||
return new SkillLoadResult(new SkillBox(toolkit), Map.of(), List.of());
|
||||
return new SkillLoadResult(createSkillBox(toolkit, workspaceDir), Map.of(), List.of());
|
||||
}
|
||||
}
|
||||
|
||||
private static SkillLoadResult handleMissingRoot(Path root, SkillsConfig skillsConfig, Toolkit toolkit) {
|
||||
private static SkillLoadResult handleMissingRoot(
|
||||
Path root,
|
||||
SkillsConfig skillsConfig,
|
||||
Toolkit toolkit,
|
||||
Path workspaceDir) {
|
||||
String message = "Skills root not found: " + root;
|
||||
if (skillsConfig.isStrict()) {
|
||||
throw new AgentConfigException(message);
|
||||
}
|
||||
LOG.warn(message);
|
||||
return new SkillLoadResult(new SkillBox(toolkit), Map.of(), List.of());
|
||||
return new SkillLoadResult(createSkillBox(toolkit, workspaceDir), Map.of(), List.of());
|
||||
}
|
||||
|
||||
private static SkillBox createSkillBox(Toolkit toolkit, Path workspaceDir) {
|
||||
SkillBox skillBox = new SkillBox(toolkit);
|
||||
if (workspaceDir != null) {
|
||||
skillBox.codeExecution()
|
||||
.workDir(workspaceDir.toAbsolutePath().normalize().toString())
|
||||
.enable();
|
||||
}
|
||||
return skillBox;
|
||||
}
|
||||
|
||||
private static List<AgentSkill> selectSkills(
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -24,7 +25,11 @@ public class SkillBoxFactoryTest {
|
||||
public void setUp() {
|
||||
cfg = new AgentConfig();
|
||||
cfg.getSkills().setEnabled(true);
|
||||
cfg.getSkills().setPath("src/test/resources/agent/skills");
|
||||
Path moduleRelative = Path.of("src/test/resources/agent/skills");
|
||||
Path rootRelative = Path.of("liteflow-testcase-el/liteflow-testcase-el-react-agent/src/test/resources/agent/skills");
|
||||
cfg.getSkills().setPath(Files.isRegularFile(moduleRelative.resolve("demo/SKILL.md"))
|
||||
? moduleRelative.toString()
|
||||
: rootRelative.toString());
|
||||
cfg.getSkills().setStrict(true);
|
||||
SkillEchoTool.reset();
|
||||
}
|
||||
@@ -72,6 +77,16 @@ public class SkillBoxFactoryTest {
|
||||
Assertions.assertEquals(1, SkillEchoTool.CONSTRUCT_COUNT.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkillBoxUsesConversationWorkspaceForCodeExecution() throws Exception {
|
||||
Path workspace = Files.createTempDirectory("liteflow-skill-workspace-test-");
|
||||
|
||||
SkillLoadResult result = SkillBoxFactory.build(new Toolkit(), cfg, List.of("demo"), workspace);
|
||||
|
||||
Assertions.assertEquals(workspace.toAbsolutePath().normalize(), result.skillBox().getCodeExecutionWorkDir());
|
||||
Assertions.assertEquals(workspace.toAbsolutePath().normalize().resolve("skills"), result.skillBox().getUploadDir());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingSkillsDirectoryFailsInStrictMode() {
|
||||
cfg.getSkills().setPath(Path.of("target", "missing-skills-dir").toString());
|
||||
|
||||
Reference in New Issue
Block a user