Skip to content
Open
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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
<jackson.version>2.16.2</jackson.version>
<snakeyaml.version>2.2</snakeyaml.version>
<commons-exec.version>1.4.0</commons-exec.version>
<lombok.version>1.18.32</lombok.version>
<lombok.version>1.18.42</lombok.version>
<slf4j.version>2.0.12</slf4j.version>
<logback.version>1.4.14</logback.version>
<caffeine.version>3.1.8</caffeine.version>
Expand Down
19 changes: 12 additions & 7 deletions src/main/java/io/leavesfly/jimi/agent/AgentSpecLoader.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package io.leavesfly.jimi.agent;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import io.leavesfly.jimi.exception.AgentSpecException;
import io.leavesfly.jimi.util.ResourceUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
Expand All @@ -15,7 +15,6 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -281,11 +280,13 @@ private AgentSpec parseAgentSpecFromResource(Map<String, Object> data, String ag
// 处理系统提示词路径 - 使用虚拟路径标识资源
if (data.containsKey("system_prompt")) {
String promptFile = (String) data.get("system_prompt");
Path virtualPath = Paths.get("classpath:agents/" + agentName + "/" + promptFile);
// Path virtualPath = Paths.get("classpath:agents/" + agentName + "/" + promptFile);
Path virtualPath = ResourceUtils.resolveFromClasspath("agents/" + agentName + "/" + promptFile);
builder.systemPromptPath(virtualPath);
} else if (data.containsKey("system_prompt_path")) {
String promptFile = (String) data.get("system_prompt_path");
Path virtualPath = Paths.get("classpath:agents/" + agentName + "/" + promptFile);
// Path virtualPath = Paths.get("classpath:agents/" + agentName + "/" + promptFile);
Path virtualPath = ResourceUtils.resolveFromClasspath("agents/" + agentName + "/" + promptFile);
builder.systemPromptPath(virtualPath);
}

Expand Down Expand Up @@ -316,7 +317,8 @@ private AgentSpec parseAgentSpecFromResource(Map<String, Object> data, String ag
for (Map.Entry<String, Map<String, Object>> entry : subagentsData.entrySet()) {
String subagentPath = (String) entry.getValue().get("path");
// 构造 classpath 虚拟路径
Path resolvedPath = Paths.get("classpath:agents/" + subagentPath);
// Path resolvedPath = Paths.get("classpath:agents/" + subagentPath);
Path resolvedPath = ResourceUtils.resolveFromClasspath("agents/" + subagentPath);

SubagentSpec subagent = SubagentSpec.builder()
.path(resolvedPath)
Expand Down Expand Up @@ -382,7 +384,10 @@ private AgentSpec parseAgentSpec(Map<String, Object> data, Path agentFile) {
for (Map.Entry<String, Map<String, Object>> entry : subagentsData.entrySet()) {
String subagentPath = (String) entry.getValue().get("path");
// 将相对路径转换为绝对路径
Path resolvedPath = agentsRootDir.resolve(subagentPath);
Path resolvedPath = agentsRootDir == null ?
Path.of(subagentPath)
:
agentsRootDir.resolve(subagentPath);

SubagentSpec subagent = SubagentSpec.builder()
.path(resolvedPath)
Expand Down Expand Up @@ -410,7 +415,7 @@ public Path getDefaultAgentPath() {
URL resource = getClass().getClassLoader().getResource(resourcePath);
if (resource != null) {
log.debug("Found default agent in classpath: {}", resourcePath);
return Paths.get("classpath:" + resourcePath);
return ResourceUtils.resolveFromClasspath(resourcePath);
}
throw new AgentSpecException("Default agent not found in classpath: " + resourcePath);
}
Expand Down
7 changes: 2 additions & 5 deletions src/main/java/io/leavesfly/jimi/skill/SkillLoader.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package io.leavesfly.jimi.skill;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.leavesfly.jimi.util.ResourceUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
Expand All @@ -17,10 +18,6 @@
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.Enumeration;

/**
* Skill加载器
Expand Down Expand Up @@ -130,7 +127,7 @@ public List<SkillSpec> loadSkillsFromClasspath(SkillScope scope) {
if (skill != null) {
skill.setScope(scope);
// 使用虚拟路径标识
skill.setSkillFilePath(Paths.get("classpath:" + resourcePath));
skill.setSkillFilePath(ResourceUtils.resolveFromClasspath(resourcePath));

skills.add(skill);
log.debug("Loaded skill from classpath: {} ({})", skill.getName(), resourcePath);
Expand Down
7 changes: 5 additions & 2 deletions src/main/java/io/leavesfly/jimi/tool/file/WriteFile.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,11 @@ public Mono<ToolResult> execute(Params params) {

try {
// 处理转义序列(将字面量 \n、\t、\r 转换为真正的控制字符)
String processedContent = unescapeContent(params.content);

// String processedContent = unescapeContent(params.content);

// 转义的逻辑感觉不对,特别是在代码场景下不需要转义,否则会造成代码有问题
String processedContent = params.content;

// 写入文件
if ("overwrite".equals(params.mode)) {
Files.writeString(targetPath, processedContent);
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/io/leavesfly/jimi/util/ResourceUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.leavesfly.jimi.util;

import io.leavesfly.jimi.exception.AgentSpecException;

import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;

public class ResourceUtils {
public static Path resolveFromClasspath(String resourcePath) {
URL resource = ResourceUtils.class.getClassLoader().getResource(resourcePath);
try {
if (resource != null) {
return Paths.get(resource.toURI());
}
} catch (URISyntaxException e) {
throw new RuntimeException("Resource resolve failed: " + resourcePath, e);
}
throw new RuntimeException("Resource not found: " + resourcePath);
}
}
29 changes: 28 additions & 1 deletion src/main/resources/.jimi/template-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,16 @@
"sleep_ms": 3000
}
},
"kimi": {
"type": "kimi",
"base_url": "https://api.moonshot.cn/v1",
"api_key": "YOUR_API_KEY_HERE",
"rate_limit": {
"window_ms": 4000,
"max_requests": 4,
"sleep_ms": 3000
}
},
"ollama": {
"type": "ollama",
"base_url": "http://localhost:11434/v1",
Expand Down Expand Up @@ -69,6 +79,21 @@
"provider": "ollama",
"model": "qwen3:4b-thinking-2507-q8_0",
"max_context_size": 100000
},
"kimi-k2-turbo-preview": {
"provider": "kimi",
"model": "kimi-k2-turbo-preview",
"max_context_size": 200000
},
"kimi-k2-thinking": {
"provider": "kimi",
"model": "kimi-k2-thinking",
"max_context_size": 200000
},
"kimi-k2-thinking-turbo": {
"provider": "kimi",
"model": "kimi-k2-thinking-turbo",
"max_context_size": 200000
}
},
"loop_control": {
Expand Down Expand Up @@ -98,7 +123,9 @@
"storage_path": ".jimi/code_graph",
"auto_load": true,
"auto_save": true,
"include_patterns": ["**/*.java"],
"include_patterns": [
"**/*.java"
],
"exclude_patterns": [
"**/test/**",
"**/tests/**",
Expand Down