Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

import io.agentscope.core.e2e.E2ETestCondition;
import io.agentscope.core.formatter.openai.OpenAIChatFormatter;
import io.agentscope.core.message.Msg;
import io.agentscope.core.message.MsgRole;
Expand All @@ -33,6 +34,7 @@
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import org.junit.jupiter.api.extension.ExtendWith;
import reactor.test.StepVerifier;

/**
Expand All @@ -52,6 +54,7 @@
*
* <p><b>Requirements:</b>
* <ul>
* <li>ENABLE_E2E_TESTS=true</li>
* <li>OPENAI_API_KEY environment variable must be set (official OpenAI API key)</li>
* <li>Active internet connection</li>
* <li>Valid OpenAI API quota</li>
Expand All @@ -62,6 +65,7 @@
@Tag("e2e")
@Tag("openai")
@Tag("official")
@ExtendWith(E2ETestCondition.class)
@DisplayName("OpenAI Official API E2E Tests (Real OpenAI API)")
@EnabledIfEnvironmentVariable(
named = "OPENAI_API_KEY",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import io.agentscope.core.agent.RuntimeContext;
import io.agentscope.harness.agent.filesystem.AbstractFilesystem;
import io.agentscope.harness.agent.filesystem.OverlayFilesystem;
import io.agentscope.harness.agent.filesystem.local.LocalFilesystem;
import io.agentscope.harness.agent.filesystem.model.FileInfo;
import io.agentscope.harness.agent.filesystem.model.GlobResult;
import io.agentscope.harness.agent.filesystem.model.ReadResult;
Expand Down Expand Up @@ -298,7 +299,7 @@ public List<Path> listKnowledgeFiles(RuntimeContext rc) {
if (glob.isSuccess() && glob.matches() != null) {
for (FileInfo fi : glob.matches()) {
if (fi.path() != null && !fi.path().isBlank()) {
relativePaths.add(normalizeRelativePath(fi.path().trim()));
relativePaths.add(normalizeListedPath(fi.path().trim()));
}
}
}
Expand Down Expand Up @@ -540,7 +541,10 @@ public Collection<TaskRecord> listAllTaskRecords(
if (fi.path() == null || fi.path().isBlank()) {
continue;
}
String rel = normalizeRelativePath(fi.path().trim());
String rel = normalizeListedPath(fi.path().trim());
if (rel.isEmpty()) {
continue;
}
Instant mtime = parseInstantQuiet(fi.modifiedAt());
relPaths.put(rel, Optional.ofNullable(mtime));
}
Expand Down Expand Up @@ -929,6 +933,64 @@ static String normalizeRelativePath(String relativePath) {
return s;
}

/**
* Normalizes a path returned by {@link AbstractFilesystem#glob} into a workspace-relative
* string when possible.
*/
private String normalizeListedPath(String path) {
if (path == null || path.isBlank()) {
return "";
}
String normalized = path.replace('\\', '/').strip();
try {
Path candidate = Path.of(normalized).normalize();
if (candidate.isAbsolute()) {
String workspaceRelative = relativizeIfUnder(candidate, workspace);
if (workspaceRelative != null) {
return workspaceRelative;
}
Path lowerRoot = getOverlayLowerRoot();
if (lowerRoot != null) {
String lowerRelative = relativizeIfUnder(candidate, lowerRoot);
if (lowerRelative != null) {
return lowerRelative;
}
}
return stripLeadingSlashes(normalized);
}
} catch (Exception ignored) {
// Fall through to the string-based fallback below.
}
return stripLeadingSlashes(normalized);
}

private String relativizeIfUnder(Path candidate, Path root) {
Path normalizedRoot = root.toAbsolutePath().normalize();
if (!candidate.startsWith(normalizedRoot)) {
return null;
}
return normalizedRoot.relativize(candidate).toString().replace('\\', '/');
}

private String stripLeadingSlashes(String value) {
String s = value;
while (s.startsWith("/")) {
s = s.substring(1);
}
return s;
}

private Path getOverlayLowerRoot() {
if (!(filesystem instanceof OverlayFilesystem overlay)) {
return null;
}
AbstractFilesystem lower = overlay.lower();
if (lower instanceof LocalFilesystem localFilesystem) {
return localFilesystem.getCwd();
}
return null;
}

/**
* Returns workspace-relative paths of all memory files ({@code MEMORY.md} and {@code
* memory/*.md}). Unions results from the {@link AbstractFilesystem} layer and the local disk,
Expand All @@ -946,7 +1008,7 @@ public List<String> listMemoryFilePaths(RuntimeContext rc) {
if (glob.isSuccess() && glob.matches() != null) {
for (FileInfo fi : glob.matches()) {
if (fi.path() != null && !fi.path().isBlank()) {
String rel = normalizeRelativePath(fi.path().trim());
String rel = normalizeListedPath(fi.path().trim());
if (!rel.isEmpty()) {
paths.add(rel);
}
Expand Down Expand Up @@ -983,7 +1045,7 @@ public List<String> listSessionLogFiles(RuntimeContext rc) {
if (glob.isSuccess() && glob.matches() != null) {
for (FileInfo fi : glob.matches()) {
if (fi.path() != null && !fi.path().isBlank()) {
String rel = normalizeRelativePath(fi.path().trim());
String rel = normalizeListedPath(fi.path().trim());
if (!rel.isEmpty()) {
paths.add(rel);
}
Expand Down
Loading
Loading