mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-15 03:55:09 +08:00
fix(memory): rebuild agent on workspace file change so memory edits apply
This commit is contained in:
parent
a27084f9cf
commit
ceb4da642b
@ -215,6 +215,20 @@ public class AgentService {
|
|||||||
agentInstances.remove(agentId);
|
agentInstances.remove(agentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invalidate the cached agent instance whenever one of its workspace files
|
||||||
|
* changes. The system prompt (which embeds MEMORY.md / PROFILE.md / structured
|
||||||
|
* memory) is baked into the cached instance at build time, so memory edits made
|
||||||
|
* via tools, consolidation, or cleanup would otherwise stay invisible until an
|
||||||
|
* agent config change or restart. Rebuilding on the next turn picks them up.
|
||||||
|
*/
|
||||||
|
@org.springframework.context.event.EventListener
|
||||||
|
public void onWorkspaceFileChanged(vip.mate.workspace.document.event.WorkspaceFileChangedEvent event) {
|
||||||
|
if (event.agentId() != null) {
|
||||||
|
agentInstances.remove(event.agentId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 运行时入口 ====================
|
// ==================== 运行时入口 ====================
|
||||||
|
|
||||||
public String chat(Long agentId, String message, String conversationId) {
|
public String chat(Long agentId, String message, String conversationId) {
|
||||||
|
|||||||
@ -3,8 +3,10 @@ package vip.mate.workspace.document;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
import vip.mate.workspace.document.event.WorkspaceFileChangedEvent;
|
||||||
import vip.mate.workspace.document.model.WorkspaceFileEntity;
|
import vip.mate.workspace.document.model.WorkspaceFileEntity;
|
||||||
import vip.mate.workspace.document.repository.WorkspaceFileMapper;
|
import vip.mate.workspace.document.repository.WorkspaceFileMapper;
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ import java.util.stream.Collectors;
|
|||||||
public class WorkspaceFileService {
|
public class WorkspaceFileService {
|
||||||
|
|
||||||
private final WorkspaceFileMapper fileMapper;
|
private final WorkspaceFileMapper fileMapper;
|
||||||
|
private final ApplicationEventPublisher eventPublisher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 列出 Agent 的所有工作区文件(按排序 + 文件名排列)
|
* 列出 Agent 的所有工作区文件(按排序 + 文件名排列)
|
||||||
@ -68,6 +71,7 @@ public class WorkspaceFileService {
|
|||||||
existing.setContent(content);
|
existing.setContent(content);
|
||||||
existing.setFileSize(size);
|
existing.setFileSize(size);
|
||||||
fileMapper.updateById(existing);
|
fileMapper.updateById(existing);
|
||||||
|
eventPublisher.publishEvent(new WorkspaceFileChangedEvent(agentId, filename));
|
||||||
return existing;
|
return existing;
|
||||||
} else {
|
} else {
|
||||||
WorkspaceFileEntity entity = new WorkspaceFileEntity();
|
WorkspaceFileEntity entity = new WorkspaceFileEntity();
|
||||||
@ -78,6 +82,7 @@ public class WorkspaceFileService {
|
|||||||
entity.setEnabled(false);
|
entity.setEnabled(false);
|
||||||
entity.setSortOrder(0);
|
entity.setSortOrder(0);
|
||||||
fileMapper.insert(entity);
|
fileMapper.insert(entity);
|
||||||
|
eventPublisher.publishEvent(new WorkspaceFileChangedEvent(agentId, filename));
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -91,6 +96,7 @@ public class WorkspaceFileService {
|
|||||||
new LambdaQueryWrapper<WorkspaceFileEntity>()
|
new LambdaQueryWrapper<WorkspaceFileEntity>()
|
||||||
.eq(WorkspaceFileEntity::getAgentId, agentId)
|
.eq(WorkspaceFileEntity::getAgentId, agentId)
|
||||||
.eq(WorkspaceFileEntity::getFilename, filename));
|
.eq(WorkspaceFileEntity::getFilename, filename));
|
||||||
|
eventPublisher.publishEvent(new WorkspaceFileChangedEvent(agentId, filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -0,0 +1,16 @@
|
|||||||
|
package vip.mate.workspace.document.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Published whenever an agent's workspace file is created, updated, or deleted.
|
||||||
|
* <p>
|
||||||
|
* Workspace files (AGENTS.md, SOUL.md, PROFILE.md, MEMORY.md, structured/*.md)
|
||||||
|
* are baked into the agent's system prompt when its runtime instance is built.
|
||||||
|
* Listeners use this to invalidate the cached agent instance so memory edits
|
||||||
|
* (tool writes, consolidation, cleanup) take effect on the next turn instead of
|
||||||
|
* only after an agent config change or restart.
|
||||||
|
*
|
||||||
|
* @param agentId the affected agent
|
||||||
|
* @param filename the workspace file that changed
|
||||||
|
*/
|
||||||
|
public record WorkspaceFileChangedEvent(Long agentId, String filename) {
|
||||||
|
}
|
||||||
@ -38,6 +38,7 @@ import static org.mockito.Mockito.when;
|
|||||||
class WorkspaceMemorySearchTest {
|
class WorkspaceMemorySearchTest {
|
||||||
|
|
||||||
@Mock private WorkspaceFileMapper fileMapper;
|
@Mock private WorkspaceFileMapper fileMapper;
|
||||||
|
@Mock private org.springframework.context.ApplicationEventPublisher eventPublisher;
|
||||||
private WorkspaceFileService service;
|
private WorkspaceFileService service;
|
||||||
|
|
||||||
@BeforeAll
|
@BeforeAll
|
||||||
@ -51,7 +52,21 @@ class WorkspaceMemorySearchTest {
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void setUp() {
|
void setUp() {
|
||||||
service = new WorkspaceFileService(fileMapper);
|
service = new WorkspaceFileService(fileMapper, eventPublisher);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("saveFile publishes a change event so the cached agent instance is invalidated")
|
||||||
|
void saveFilePublishesChangeEvent() {
|
||||||
|
when(fileMapper.selectOne(any())).thenReturn(null); // new file path
|
||||||
|
|
||||||
|
service.saveFile(1000000001L, "MEMORY.md", "## 稳定事实\n- 用户语言:简体中文");
|
||||||
|
|
||||||
|
ArgumentCaptor<vip.mate.workspace.document.event.WorkspaceFileChangedEvent> captor =
|
||||||
|
ArgumentCaptor.forClass(vip.mate.workspace.document.event.WorkspaceFileChangedEvent.class);
|
||||||
|
org.mockito.Mockito.verify(eventPublisher).publishEvent(captor.capture());
|
||||||
|
assertThat(captor.getValue().agentId()).isEqualTo(1000000001L);
|
||||||
|
assertThat(captor.getValue().filename()).isEqualTo("MEMORY.md");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------- tokenize ----------
|
// ---------- tokenize ----------
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user