Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import io.agentscope.harness.agent.filesystem.remote.store.NamespaceFactory;
import io.agentscope.harness.agent.filesystem.sandbox.SandboxBackedFilesystem;
import io.agentscope.harness.agent.filesystem.spec.LocalFilesystemSpec;
import io.agentscope.harness.agent.memory.MemoryConfig;
import io.agentscope.harness.agent.memory.compaction.CompactionConfig;
import io.agentscope.harness.agent.memory.compaction.ToolResultEvictionConfig;
import io.agentscope.harness.agent.middleware.DynamicSubagentsMiddleware;
Expand Down Expand Up @@ -311,6 +312,7 @@ static SubagentFactory buildGeneralPurposeFactory(
final boolean capturedAgentTracingLogEnabled = b.agentTracingLogEnabled;
final List<String> capturedAdditionalContextFiles = List.copyOf(b.additionalContextFiles);
final int capturedMaxContextTokens = b.maxContextTokens;
final MemoryConfig capturedMemoryConfig = b.memoryConfig;
// Propagate the parent's (distributed) state store so an exposed subagent can be
// re-materialized on another node / after a restart and still load its conversation
// history by sessionId. Null in purely local default deployments — children then keep
Expand Down Expand Up @@ -356,6 +358,7 @@ static SubagentFactory buildGeneralPurposeFactory(
if (capturedModelExec != null) sub.modelExecutionConfig(capturedModelExec);
if (capturedToolExec != null) sub.toolExecutionConfig(capturedToolExec);
if (capturedGenOpts != null) sub.generateOptions(capturedGenOpts);
sub.memory(capturedMemoryConfig);
if (capturedDisableCompaction) {
sub.disableCompaction();
} else if (capturedCompactionConfig != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import io.agentscope.harness.agent.filesystem.local.LocalFilesystem;
import io.agentscope.harness.agent.filesystem.remote.store.InMemoryStore;
import io.agentscope.harness.agent.filesystem.spec.RemoteFilesystemSpec;
import io.agentscope.harness.agent.memory.MemoryConfig;
import io.agentscope.harness.agent.memory.compaction.CompactionConfig;
import io.agentscope.harness.agent.middleware.AgentTraceMiddleware;
import io.agentscope.harness.agent.middleware.SubagentEntry;
Expand Down Expand Up @@ -1181,6 +1182,76 @@ void generalPurpose_mirrorCompactionConfig() throws Exception {
assertNotNull(child.getCompactionHook(), "CompactionHook should be mirrored to GP child");
}

@Test
void generalPurpose_inheritsMemoryConfig_fromParent() throws Exception {
Files.createDirectories(workspace);

Model parentModel = stubModel("ok");
Model memoryModel = mock(Model.class);
when(memoryModel.getModelName()).thenReturn("memory-model");
ChatResponse memoryChunk =
new ChatResponse(
"memory-id",
List.of(TextBlock.builder().text("memory-done").build()),
null,
Map.of(),
"stop");
when(memoryModel.stream(anyList(), anyList(), any())).thenReturn(Flux.just(memoryChunk));

MemoryConfig memoryConfig =
MemoryConfig.builder()
.model(memoryModel)
.consolidationMinGap(Duration.ofMinutes(1))
.build();

List<SubagentEntry> entries =
HarnessAgent.builder()
.model(parentModel)
.workspace(workspace)
.memory(memoryConfig)
.buildSubagentEntries(workspace);

HarnessAgent child =
(HarnessAgent)
entries.stream()
.filter(e -> "general-purpose".equals(e.name()))
.findFirst()
.orElseThrow()
.factory()
.create(RuntimeContext.empty());

child.call(userText("hi, keep this in memory"), RuntimeContext.empty()).block();

verify(memoryModel).stream(any(), any(), any());
verify(parentModel, atLeast(1)).stream(any(), any(), any());
}

@Test
void generalPurpose_withoutMemoryConfig_usesParentModelOnly() throws Exception {
Files.createDirectories(workspace);

Model parentModel = stubModel("ok");

List<SubagentEntry> entries =
HarnessAgent.builder()
.model(parentModel)
.workspace(workspace)
.buildSubagentEntries(workspace);

HarnessAgent child =
(HarnessAgent)
entries.stream()
.filter(e -> "general-purpose".equals(e.name()))
.findFirst()
.orElseThrow()
.factory()
.create(RuntimeContext.empty());

child.call(userText("hi, no memory config"), RuntimeContext.empty()).block();

verify(parentModel, atLeast(1)).stream(any(), any(), any());
}

// =========================================================================
// Multiple declarations → same definition workspace
// =========================================================================
Expand Down
Loading