diff --git a/agentscope-harness/src/main/java/io/agentscope/harness/agent/filesystem/remote/RemoteFilesystem.java b/agentscope-harness/src/main/java/io/agentscope/harness/agent/filesystem/remote/RemoteFilesystem.java index 57efde917d..e6131d5213 100644 --- a/agentscope-harness/src/main/java/io/agentscope/harness/agent/filesystem/remote/RemoteFilesystem.java +++ b/agentscope-harness/src/main/java/io/agentscope/harness/agent/filesystem/remote/RemoteFilesystem.java @@ -33,6 +33,9 @@ import io.agentscope.harness.agent.filesystem.remote.store.StoreItem; import io.agentscope.harness.agent.filesystem.util.FilesystemUtils; import io.agentscope.harness.agent.workspace.WorkspaceIndex; +import java.nio.ByteBuffer; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; import java.nio.file.FileSystems; import java.nio.file.Path; @@ -503,9 +506,15 @@ public List uploadFiles( String contentStr; String encoding; try { - contentStr = new String(content, StandardCharsets.UTF_8); + contentStr = + StandardCharsets.UTF_8 + .newDecoder() + .onMalformedInput(CodingErrorAction.REPORT) + .onUnmappableCharacter(CodingErrorAction.REPORT) + .decode(ByteBuffer.wrap(content)) + .toString(); encoding = "utf-8"; - } catch (Exception e) { + } catch (CharacterCodingException e) { contentStr = Base64.getEncoder().encodeToString(content); encoding = "base64"; } diff --git a/agentscope-harness/src/test/java/io/agentscope/harness/agent/filesystem/RemoteFilesystemCASTest.java b/agentscope-harness/src/test/java/io/agentscope/harness/agent/filesystem/RemoteFilesystemCASTest.java index d8a4f676f4..5c6d7b1ffc 100644 --- a/agentscope-harness/src/test/java/io/agentscope/harness/agent/filesystem/RemoteFilesystemCASTest.java +++ b/agentscope-harness/src/test/java/io/agentscope/harness/agent/filesystem/RemoteFilesystemCASTest.java @@ -218,6 +218,24 @@ void uploadFiles_repeatedOnSamePath_returnsSuccessEachTime() { assertEquals("iter-4", read.fileData().content()); } + @Test + void uploadFiles_nonUtf8Binary_roundTripsWithoutCorruption() { + InMemoryStore store = new InMemoryStore(); + RemoteFilesystem fs = newFs(store); + byte[] expected = new byte[] {0, (byte) 0xff, 1, (byte) 0x80}; + + List upload = + fs.uploadFiles(CTX, List.of(Map.entry("/image.png", expected))); + assertEquals(1, upload.size()); + assertTrue(upload.get(0).isSuccess(), () -> "upload failed: " + upload.get(0).error()); + + var download = fs.downloadFiles(CTX, List.of("/image.png")); + assertEquals(1, download.size()); + assertTrue( + download.get(0).isSuccess(), () -> "download failed: " + download.get(0).error()); + assertArrayEquals(expected, download.get(0).content()); + } + @Test void downloadFiles_decodesWrappedBase64Content() { InMemoryStore store = new InMemoryStore();