fix(memory): scope memory endpoints to active profile and auto-reload on profile switch (#1035)

Co-authored-by: M57 <hy4ri@users.noreply.github.com>
This commit is contained in:
M57andM57 authored and GitHub committed 2026-09-01 19:20:18 +03:00
1 parent 11dd1eff92
commit 21db9bfdab
4 files changed
+63 -2

No files matched your search

@@ -118,6 +118,19 @@ class ProfileScopeInterceptorTest {
assertEquals("alpha", url.queryParameter("profile"))
}
@Test
fun memoryEndpoints_areScoped() {
val client = clientFor("yasmin")
for (path in listOf("api/memory", "api/memory/learning-graph", "api/memory/providers/mem0/config")) {
server.enqueue(MockResponse().setResponseCode(200).setBody("{}"))
val req = Request.Builder().url(server.url(path)).build()
client.newCall(req).execute().close()
val url = server.takeRequest().requestUrl!!
assertEquals("yasmin", url.queryParameter("profile"))
assertEquals("/$path", url.encodedPath)
}
}
@Test
fun lookalikePath_notScoped() {
// Sourcery review (PR #540): `startsWith` must not match non-segment
@@ -6,6 +6,7 @@ import com.m57.hermescontrol.data.model.MemoryResetResponse
import com.m57.hermescontrol.data.model.MemoryResponse
import com.m57.hermescontrol.data.remote.ApiClient
import com.m57.hermescontrol.data.remote.HermesApiService
import com.m57.hermescontrol.data.session.ProfileSwitchCoordinator
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.every
@@ -14,6 +15,7 @@ import io.mockk.mockkObject
import io.mockk.unmockkAll
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.resetMain
@@ -36,6 +38,8 @@ import retrofit2.Response
class MemoryViewModelTest {
private val testDispatcher = StandardTestDispatcher()
private lateinit var mockApi: HermesApiService
private val mockSwitchFlow = MutableSharedFlow<String>(extraBufferCapacity = 1)
private val mockConnSwitchFlow = MutableSharedFlow<String>(extraBufferCapacity = 1)
private val memoryResponse =
MemoryResponse(
@@ -56,6 +60,9 @@ class MemoryViewModelTest {
fun setUp() {
Dispatchers.setMain(testDispatcher)
mockkObject(ApiClient)
mockkObject(ProfileSwitchCoordinator)
every { ProfileSwitchCoordinator.switched } returns mockSwitchFlow
every { ProfileSwitchCoordinator.connectionSwitched } returns mockConnSwitchFlow
mockApi = mockk(relaxed = true)
every { ApiClient.hermesApi } returns mockApi
coEvery { mockApi.getMemory() } returns Response.success(memoryResponse)
@@ -79,6 +86,30 @@ class MemoryViewModelTest {
assertEquals(1024L, state.memory?.builtin_files?.memory)
}
@Test
fun `profile switch triggers silent reload`() {
val vm = MemoryViewModel()
testDispatcher.scheduler.advanceUntilIdle()
coVerify(exactly = 0) { mockApi.getMemory() }
mockSwitchFlow.tryEmit("yasmin")
testDispatcher.scheduler.advanceUntilIdle()
coVerify(exactly = 1) { mockApi.getMemory() }
}
@Test
fun `connection profile switch triggers silent reload`() {
val vm = MemoryViewModel()
testDispatcher.scheduler.advanceUntilIdle()
coVerify(exactly = 0) { mockApi.getMemory() }
mockConnSwitchFlow.tryEmit("server-remote")
testDispatcher.scheduler.advanceUntilIdle()
coVerify(exactly = 1) { mockApi.getMemory() }
}
@Test
fun `load also fetches learning graph for self-improvement section`() {
val graph =