fix issue #1738 problem 1#1773
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
AgentScopeJavaBot
left a comment
There was a problem hiding this comment.
🤖 AI Review
This PR adds a resources parameter to the SkillManageTool.create action, enabling atomic creation of a skill with all its resource files in a single tool call. This directly addresses the race condition described in issue #1738 where an agent calls create then immediately write_file in the same reasoning turn and encounters "Skill not found" errors. The implementation is clean — it leverages the existing SkillUtil.createFrom(content, resources, source) and WorkspaceSkillRepository.writeSkill() infrastructure that already supports multi-file atomic writes. A comprehensive set of new tests (209 lines) covers the happy path, edge cases (null/empty resources, invalid paths, multiple resource types), and draft-mode behavior. The code follows existing patterns consistently.
| for (Map.Entry<?, ?> entry : ((Map<?, ?>) v).entrySet()) { | ||
| if (entry.getKey() instanceof String && entry.getValue() instanceof String) { | ||
| result.put((String) entry.getKey(), (String) entry.getValue()); | ||
| } |
There was a problem hiding this comment.
[minor] mapOfStrings silently drops entries whose key or value is not a String. If an LLM passes a non-string value (e.g., {"scripts/count.sh": 42}), that resource is omitted without any error or warning — the tool returns success and the agent assumes the file was created. Consider logging a warning when an entry is skipped, so the issue surfaces in diagnostics:
if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
result.put((String) entry.getKey(), (String) entry.getValue());
} else {
log.warn("mapOfStrings: skipping non-String entry key={}", entry.getKey());
}| properties.put( | ||
| "resources", | ||
| Map.of( | ||
| "type", | ||
| "object", | ||
| "description", | ||
| "Optional for create: supporting files to include with the skill. " | ||
| + "Keys are paths relative to skill root (must start with " | ||
| + "references/, templates/, scripts/, or assets/), " | ||
| + "values are file contents. All files written atomically " | ||
| + "with SKILL.md.")); |
There was a problem hiding this comment.
[nit] The JSON schema for resources declares "type": "object" but omits additionalProperties. Adding "additionalProperties", Map.of("type", "string") would give the LLM a stronger hint that values must be strings, and would enable schema-level validation on the tool-call side. Not blocking — the description already conveys the intent clearly.
AgentScopeJavaBot
left a comment
There was a problem hiding this comment.
🤖 AI Review
This PR adds a resources parameter to the SkillManageTool.create action, enabling atomic creation of a skill with all its resource files in a single tool call. This directly addresses the race condition described in issue #1738 where an agent calls create then immediately write_file in the same reasoning turn and encounters "Skill not found" errors. The implementation is clean — it leverages the existing SkillUtil.createFrom(content, resources, source) and WorkspaceSkillRepository.writeSkill() infrastructure that already supports multi-file atomic writes. A comprehensive set of new tests (209 lines) covers the happy path, edge cases (null/empty resources, invalid paths, multiple resource types), and draft-mode behavior. The code follows existing patterns consistently.
| for (Map.Entry<?, ?> entry : ((Map<?, ?>) v).entrySet()) { | ||
| if (entry.getKey() instanceof String && entry.getValue() instanceof String) { | ||
| result.put((String) entry.getKey(), (String) entry.getValue()); | ||
| } |
There was a problem hiding this comment.
[minor] mapOfStrings silently drops entries whose key or value is not a String. If an LLM passes a non-string value (e.g., {"scripts/count.sh": 42}), that resource is omitted without any error or warning — the tool returns success and the agent assumes the file was created. Consider logging a warning when an entry is skipped, so the issue surfaces in diagnostics:
if (entry.getKey() instanceof String && entry.getValue() instanceof String) {
result.put((String) entry.getKey(), (String) entry.getValue());
} else {
log.warn("mapOfStrings: skipping non-String entry key={}", entry.getKey());
}| properties.put( | ||
| "resources", | ||
| Map.of( | ||
| "type", | ||
| "object", | ||
| "description", | ||
| "Optional for create: supporting files to include with the skill. " | ||
| + "Keys are paths relative to skill root (must start with " | ||
| + "references/, templates/, scripts/, or assets/), " | ||
| + "values are file contents. All files written atomically " | ||
| + "with SKILL.md.")); |
There was a problem hiding this comment.
[nit] The JSON schema for resources declares "type": "object" but omits additionalProperties. Adding "additionalProperties", Map.of("type", "string") would give the LLM a stronger hint that values must be strings, and would enable schema-level validation on the tool-call side. Not blocking — the description already conveys the intent clearly.
AgentScope-Java Version
[INFO] io.agentscope:agentscope-parent:pom:2.0.0-SNAPSHOT
Description
Background
Agent calls skill_manage create to create a skill, then immediately calls skill_manage write_file in the same reasoning turn to write resource files, resulting in "Skill not found" error
Solution
Optimize the usage pattern to avoid "create-then-immediately-write" multiple operations in the same reasoning turn:
Add resources parameter to SkillManageTool.create for atomic writing:
Checklist
Please check the following items before code is ready to be reviewed.
mvn spotless:applymvn test)