mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-11-02 14:11:49 +08:00
fix(chat): preserve directory attachments during upload validation
Follow up #652 by excluding blank stored names from upload validation and covering directory attachments with a regression test. Update caption persistence mocks for the origin-aware method. Verified with 148 targeted tests.
This commit is contained in:
parent
6f13a70709
commit
6647312162
@ -2126,7 +2126,7 @@ public class ChatController {
|
||||
List<MessageContentPart> parts) {
|
||||
if (parts == null) return;
|
||||
for (MessageContentPart part : parts) {
|
||||
if (part == null || part.getStoredName() == null) continue;
|
||||
if (part == null || part.getStoredName() == null || part.getStoredName().isBlank()) continue;
|
||||
Path file = uploadLocationResolver.resolveExistingFile(origin, part.getStoredName());
|
||||
if (file == null) {
|
||||
throw new IllegalArgumentException("聊天附件不存在或不属于当前会话");
|
||||
|
||||
@ -64,7 +64,7 @@ class BaseAgentImageCaptionPersistTest {
|
||||
h.agent.callBuildCurrentTurn(msg, "报错的行号是多少");
|
||||
|
||||
ArgumentCaptor<String> question = ArgumentCaptor.forClass(String.class);
|
||||
verify(h.caption).caption(any(), any(), any(), question.capture());
|
||||
verify(h.caption).caption(any(), any(), any(), question.capture(), any());
|
||||
assertEquals("报错的行号是多少", question.getValue(),
|
||||
"the user's question (text part) must drive a context-aware caption");
|
||||
}
|
||||
@ -81,7 +81,7 @@ class BaseAgentImageCaptionPersistTest {
|
||||
h.agent.callBuildCurrentTurn(msg, "[图片]");
|
||||
|
||||
ArgumentCaptor<String> question = ArgumentCaptor.forClass(String.class);
|
||||
verify(h.caption).caption(any(), any(), any(), question.capture());
|
||||
verify(h.caption).caption(any(), any(), any(), question.capture(), any());
|
||||
assertEquals(null, question.getValue(),
|
||||
"no text part → null question → caption falls back to generic description");
|
||||
}
|
||||
@ -115,7 +115,7 @@ class BaseAgentImageCaptionPersistTest {
|
||||
MultimodalRoutingDecision.sidecar(sidecar,
|
||||
EnumSet.of(ModelCapabilityService.Modality.VISION),
|
||||
EnumSet.of(ModelCapabilityService.Modality.VISION)));
|
||||
when(caption.caption(any(), any(), any(), any()))
|
||||
when(caption.caption(any(), any(), any(), any(), any()))
|
||||
.thenReturn(MediaCaptionService.CaptionResult.success(DESCRIPTION, 12L, false));
|
||||
|
||||
TestAgent agent = new TestAgent(conv);
|
||||
|
||||
@ -20,6 +20,27 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*/
|
||||
class ChatControllerUploadPathTest {
|
||||
|
||||
@Test
|
||||
void directoryAttachmentWithEmptyStoredNameIsNotAnUpload() throws Exception {
|
||||
ChatController controller = org.mockito.Mockito.mock(ChatController.class,
|
||||
org.mockito.Mockito.CALLS_REAL_METHODS);
|
||||
var resolver = org.mockito.Mockito.mock(
|
||||
vip.mate.workspace.core.service.ChatUploadLocationResolver.class);
|
||||
org.springframework.test.util.ReflectionTestUtils.setField(controller, "uploadLocationResolver", resolver);
|
||||
var part = new vip.mate.workspace.conversation.model.MessageContentPart();
|
||||
part.setType("file");
|
||||
part.setContentType("inode/directory");
|
||||
part.setStoredName("");
|
||||
part.setPath("/workspace/project");
|
||||
var origin = vip.mate.agent.context.ChatOrigin.web("conv", "alice", 7L, null);
|
||||
|
||||
org.junit.jupiter.api.Assertions.assertDoesNotThrow(() ->
|
||||
org.springframework.test.util.ReflectionTestUtils.invokeMethod(controller,
|
||||
"validateUploadedParts", "conv", origin, java.util.List.of(part)));
|
||||
assertThat(part.getPath()).isEqualTo("/workspace/project");
|
||||
org.mockito.Mockito.verifyNoInteractions(resolver);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("default root: returns chat-uploads/{convId}/{storedName}, not absolute")
|
||||
void defaultRootIsRelative() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user