feat(core): add AgentConfig POJOs for ReAct agent configuration

Introduce AgentConfig and nested POJOs (WorkspaceConfig, SessionConfig,
ShellConfig, DefaultsConfig, PlatformCredential, ShellMode) as pure data
holders with sensible defaults and zero third-party dependencies. Add
JUnit 5 test dependency and surefire override to liteflow-core for TDD.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
everywhere.z
2026-04-19 19:08:23 +08:00
parent 3751739b26
commit b64706c26a
9 changed files with 198 additions and 0 deletions

View File

@@ -72,5 +72,22 @@
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skipTests>false</skipTests>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,35 @@
package com.yomahub.liteflow.property.agent;
import java.util.LinkedHashMap;
import java.util.Map;
public class AgentConfig {
private WorkspaceConfig workspace = new WorkspaceConfig();
private SessionConfig session = new SessionConfig();
private ShellConfig shell = new ShellConfig();
private DefaultsConfig defaults = new DefaultsConfig();
private PlatformCredential openai = new PlatformCredential();
private PlatformCredential anthropic = new PlatformCredential();
private PlatformCredential gemini = new PlatformCredential();
private PlatformCredential dashscope = new PlatformCredential();
private Map<String, PlatformCredential> openaiCompatible = new LinkedHashMap<>();
public WorkspaceConfig getWorkspace() { return workspace; }
public void setWorkspace(WorkspaceConfig v) { this.workspace = v; }
public SessionConfig getSession() { return session; }
public void setSession(SessionConfig v) { this.session = v; }
public ShellConfig getShell() { return shell; }
public void setShell(ShellConfig v) { this.shell = v; }
public DefaultsConfig getDefaults() { return defaults; }
public void setDefaults(DefaultsConfig v) { this.defaults = v; }
public PlatformCredential getOpenai() { return openai; }
public void setOpenai(PlatformCredential v) { this.openai = v; }
public PlatformCredential getAnthropic() { return anthropic; }
public void setAnthropic(PlatformCredential v) { this.anthropic = v; }
public PlatformCredential getGemini() { return gemini; }
public void setGemini(PlatformCredential v) { this.gemini = v; }
public PlatformCredential getDashscope() { return dashscope; }
public void setDashscope(PlatformCredential v) { this.dashscope = v; }
public Map<String, PlatformCredential> getOpenaiCompatible() { return openaiCompatible; }
public void setOpenaiCompatible(Map<String, PlatformCredential> v) { this.openaiCompatible = v; }
}

View File

@@ -0,0 +1,8 @@
package com.yomahub.liteflow.property.agent;
public class DefaultsConfig {
private int maxIterations = 15;
public int getMaxIterations() { return maxIterations; }
public void setMaxIterations(int v) { this.maxIterations = v; }
}

View File

@@ -0,0 +1,17 @@
package com.yomahub.liteflow.property.agent;
import java.util.LinkedHashMap;
import java.util.Map;
public class PlatformCredential {
private String apiKey;
private String baseUrl;
private Map<String, String> extra = new LinkedHashMap<>();
public String getApiKey() { return apiKey; }
public void setApiKey(String apiKey) { this.apiKey = apiKey; }
public String getBaseUrl() { return baseUrl; }
public void setBaseUrl(String baseUrl) { this.baseUrl = baseUrl; }
public Map<String, String> getExtra() { return extra; }
public void setExtra(Map<String, String> extra) { this.extra = extra; }
}

View File

@@ -0,0 +1,16 @@
package com.yomahub.liteflow.property.agent;
import java.time.Duration;
public class SessionConfig {
private Duration idleTimeout = Duration.ofMinutes(30);
private Duration cleanupInterval = Duration.ofMinutes(1);
private int maxSessions = 10_000;
public Duration getIdleTimeout() { return idleTimeout; }
public void setIdleTimeout(Duration v) { this.idleTimeout = v; }
public Duration getCleanupInterval() { return cleanupInterval; }
public void setCleanupInterval(Duration v) { this.cleanupInterval = v; }
public int getMaxSessions() { return maxSessions; }
public void setMaxSessions(int v) { this.maxSessions = v; }
}

View File

@@ -0,0 +1,25 @@
package com.yomahub.liteflow.property.agent;
import java.time.Duration;
import java.util.Arrays;
import java.util.List;
public class ShellConfig {
private ShellMode mode = ShellMode.WHITELIST;
private List<String> whitelist = Arrays.asList(
"ls", "cat", "grep", "find", "head", "tail", "wc", "sed", "awk", "python3", "node");
private List<String> blacklist = Arrays.asList("rm", "sudo", "shutdown", "mkfs", "dd");
private Duration timeout = Duration.ofSeconds(30);
private long maxOutputBytes = 1024L * 1024;
public ShellMode getMode() { return mode; }
public void setMode(ShellMode v) { this.mode = v; }
public List<String> getWhitelist() { return whitelist; }
public void setWhitelist(List<String> v) { this.whitelist = v; }
public List<String> getBlacklist() { return blacklist; }
public void setBlacklist(List<String> v) { this.blacklist = v; }
public Duration getTimeout() { return timeout; }
public void setTimeout(Duration v) { this.timeout = v; }
public long getMaxOutputBytes() { return maxOutputBytes; }
public void setMaxOutputBytes(long v) { this.maxOutputBytes = v; }
}

View File

@@ -0,0 +1,7 @@
package com.yomahub.liteflow.property.agent;
public enum ShellMode {
WHITELIST,
BLACKLIST,
DISABLED
}

View File

@@ -0,0 +1,23 @@
package com.yomahub.liteflow.property.agent;
public class WorkspaceConfig {
private String root;
private boolean autoCreate = true;
private boolean cleanupOnSessionExpire = true;
private boolean cleanupOnJvmShutdown = false;
private long maxFileBytes = 10L * 1024 * 1024;
private int maxListSize = 1000;
public String getRoot() { return root; }
public void setRoot(String root) { this.root = root; }
public boolean isAutoCreate() { return autoCreate; }
public void setAutoCreate(boolean autoCreate) { this.autoCreate = autoCreate; }
public boolean isCleanupOnSessionExpire() { return cleanupOnSessionExpire; }
public void setCleanupOnSessionExpire(boolean v) { this.cleanupOnSessionExpire = v; }
public boolean isCleanupOnJvmShutdown() { return cleanupOnJvmShutdown; }
public void setCleanupOnJvmShutdown(boolean v) { this.cleanupOnJvmShutdown = v; }
public long getMaxFileBytes() { return maxFileBytes; }
public void setMaxFileBytes(long v) { this.maxFileBytes = v; }
public int getMaxListSize() { return maxListSize; }
public void setMaxListSize(int v) { this.maxListSize = v; }
}

View File

@@ -0,0 +1,50 @@
package com.yomahub.liteflow.property.agent;
import org.junit.jupiter.api.Test;
import java.time.Duration;
import static org.junit.jupiter.api.Assertions.*;
class AgentConfigTest {
@Test
void defaults_are_sensible() {
AgentConfig c = new AgentConfig();
assertNotNull(c.getWorkspace());
assertNotNull(c.getSession());
assertNotNull(c.getShell());
assertNotNull(c.getDefaults());
assertNotNull(c.getOpenaiCompatible());
assertTrue(c.getOpenaiCompatible().isEmpty());
WorkspaceConfig w = c.getWorkspace();
assertNull(w.getRoot());
assertTrue(w.isAutoCreate());
assertTrue(w.isCleanupOnSessionExpire());
assertFalse(w.isCleanupOnJvmShutdown());
assertEquals(10 * 1024 * 1024, w.getMaxFileBytes());
assertEquals(1000, w.getMaxListSize());
SessionConfig s = c.getSession();
assertEquals(Duration.ofMinutes(30), s.getIdleTimeout());
assertEquals(Duration.ofMinutes(1), s.getCleanupInterval());
assertEquals(10_000, s.getMaxSessions());
ShellConfig sh = c.getShell();
assertEquals(ShellMode.WHITELIST, sh.getMode());
assertNotNull(sh.getWhitelist());
assertNotNull(sh.getBlacklist());
assertEquals(Duration.ofSeconds(30), sh.getTimeout());
assertEquals(1024 * 1024, sh.getMaxOutputBytes());
assertEquals(15, c.getDefaults().getMaxIterations());
}
@Test
void platform_credentials_are_independent_instances() {
AgentConfig c = new AgentConfig();
c.getOpenai().setApiKey("k1");
assertNull(c.getAnthropic().getApiKey());
assertNull(c.getGemini().getApiKey());
assertNull(c.getDashscope().getApiKey());
}
}