Skip to content

fix(builder): fall back to LocalFilesystemSpec when no distributed AgentStateStore is configured#1841

Merged
chickenlj merged 7 commits into
agentscope-ai:mainfrom
chang6666:main
Jun 25, 2026
Merged

fix(builder): fall back to LocalFilesystemSpec when no distributed AgentStateStore is configured#1841
chickenlj merged 7 commits into
agentscope-ai:mainfrom
chang6666:main

Conversation

@chang6666

@chang6666 chang6666 commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

BuilderConfig unconditionally wired every agent with RemoteFilesystemSpec but fell back to InMemoryAgentStateStore when no distributed AgentStateStore bean was present. HarnessAgent rejects this combination, so the app could never start on a fresh checkout with the default H2 datasource.

Now when the effective AgentStateStore is local (InMemory/JsonFile), LocalFilesystemSpec is used instead, producing a consistent local-mode topology. Distributed deployments are unaffected — RemoteFilesystemSpec is still used when a distributed AgentStateStore (Redis/MySQL/etc.) is present.

Related Issue

Fixes #1840

AgentScope-Java Version

2.0.0-SNAPSHOT

Description

Background

BuilderConfig configures the filesystem spec for every agent during startup. The previous implementation unconditionally used RemoteFilesystemSpec, and fell back to InMemoryAgentStateStore when no distributed AgentStateStore bean was injected. However, HarnessAgent validates the store-vs-filesystem topology at build time — RemoteFilesystemSpec requires a distributed store that can be shared across pods, while InMemoryAgentStateStore is in-process and not shareable.

Problem

On a fresh checkout with the default H2 datasource (i.e. no Redis/MySQL distributed AgentStateStore bean injected), the harness throws IllegalStateException due to the topology mismatch, so BuilderApp cannot start at all. This is an out-of-the-box usability bug.

Changes Made

File: agentscope-examples/agents/agentscope-builder/src/main/java/io/agentscope/builder/web/config/BuilderConfig.java (+38 / -12)

  1. Added imports: io.agentscope.core.state.JsonFileAgentStateStore and io.agentscope.harness.agent.filesystem.spec.LocalFilesystemSpec.
  2. Added helper method isLocalStateStore(AgentStateStore): returns true when the store is InMemoryAgentStateStore or JsonFileAgentStateStore.
  3. Refactored the filesystem wiring in configureAllAgents:
    • When the effective store is local, use LocalFilesystemSpec with IsolationScope.USER (no shared prefix, since there is no cross-pod sharing in local mode).
    • When the effective store is distributed, keep the original behavior using RemoteFilesystemSpec(baseStore) with the activity/ shared prefix.
  4. Added INFO logs recording which filesystem spec is in effect, to aid deployment troubleshooting.
  5. Refined the existing WARN message: "DistributedStore" → "distributed AgentStateStore bean" for accuracy.

How to Test

Local mode (default H2) — verify the fix:

cd agentscope-examples/agents/agentscope-builder
mvn spring-boot:run

Expected: the app starts normally; logs show Effective AgentStateStore is local (InMemoryAgentStateStore); using LocalFilesystemSpec.; no IllegalStateException. Open the builder UI, create an agent, and start a conversation to verify filesystem writes succeed.

Distributed mode (Redis) — verify no regression:

Inject a distributed AgentStateStore bean (e.g. from agentscope-extensions-redis) and start:

mvn spring-boot:run -Dspring-boot.run.profiles=redis

Expected: logs show Effective AgentStateStore is distributed (...); using RemoteFilesystemSpec.; behavior is unchanged from before the fix; activity/ still goes to the shared BaseStore.

Regression tests:

mvn -pl agentscope-examples/agents/agentscope-builder test

Checklist

Please check the following items before code is ready to be reviewed.

  • Code has been formatted with mvn spotless:apply
  • All tests are passing (mvn test)
  • Javadoc comments are complete and follow project conventions
  • Related documentation has been updated (e.g. links, examples, etc.)
  • Code is ready for review

…entStateStore is configured

BuilderConfig unconditionally wired every agent with RemoteFilesystemSpec
but fell back to InMemoryAgentStateStore when no distributed AgentStateStore
bean was present. HarnessAgent rejects this combination, so the app could
never start on a fresh checkout with the default H2 datasource.

Now when the effective AgentStateStore is local (InMemory/JsonFile),
LocalFilesystemSpec is used instead, producing a consistent local-mode
topology. Distributed deployments are unaffected — RemoteFilesystemSpec is
still used when a distributed AgentStateStore (Redis/MySQL/etc.) is present.
@chang6666 chang6666 requested a review from a team June 19, 2026 07:04
@chang6666

chang6666 commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

fix issue #1840

…entStateStore is configured

BuilderConfig unconditionally wired every agent with RemoteFilesystemSpec
but fell back to InMemoryAgentStateStore when no distributed AgentStateStore
bean was present. HarnessAgent rejects this combination, so the app could
never start on a fresh checkout with the default H2 datasource.

Now when the effective AgentStateStore is local (InMemory/JsonFile),
LocalFilesystemSpec is used instead, producing a consistent local-mode
topology. Distributed deployments are unaffected — RemoteFilesystemSpec is
still used when a distributed AgentStateStore (Redis/MySQL/etc.) is present.
# Conflicts:
#	agentscope-examples/agents/agentscope-builder/src/main/java/io/agentscope/builder/web/config/BuilderConfig.java
@AgentScopeJavaBot AgentScopeJavaBot added bug Something isn't working area/examples agentscope-examples labels Jun 19, 2026

@AgentScopeJavaBot AgentScopeJavaBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI Review

This PR fixes a genuine out-of-the-box startup failure where BuilderConfig unconditionally wired RemoteFilesystemSpec but fell back to InMemoryAgentStateStore when no distributed store was available — a combination HarnessAgent correctly rejects. The fix is clean and well-scoped: a new isLocalStateStore() helper detects local stores and switches to LocalFilesystemSpec, producing a consistent local-mode topology. The existing test (BuilderAppContextLoadTest) remains unaffected because its Mockito proxy is typed as AgentStateStore (not InMemoryAgentStateStore), so it still takes the RemoteFilesystemSpec path. One recommended improvement: the whitelist-based instanceof check is fragile — any future local AgentStateStore implementation will silently fall into the distributed branch and reproduce the original bug.

* {@link RemoteFilesystemSpec}.
*/
private static boolean isLocalStateStore(AgentStateStore store) {
return store instanceof InMemoryAgentStateStore || store instanceof JsonFileAgentStateStore;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[major] The whitelist-based detection (instanceof InMemoryAgentStateStore || instanceof JsonFileAgentStateStore) is fragile: if a new local AgentStateStore implementation is added (e.g. an embedded SQLite store), it will silently fall into the distributed branch and reproduce the exact topology-mismatch bug this PR fixes.

Consider either:

  1. Adding a marker interface or method on AgentStateStore itself, e.g. default boolean isDistributed() { return true; }, overridden to false by local implementations; or
  2. Inverting to a blacklist of known distributed stores:
private static boolean isLocalStateStore(AgentStateStore store) {
    return !(store instanceof MysqlAgentStateStore
            || store instanceof RedisAgentStateStore
            || store instanceof JedisAgentStateStore
            || store instanceof RedissonAgentStateStore
            || store instanceof OssAgentStateStore);
}

Option 1 is more robust and pushes the classification to where it belongs (the store contract). Option 2 is a quick improvement if changing the interface is out of scope for this PR.

.addSharedPrefix("activity/"));
if (localStore) {
b.filesystem(new LocalFilesystemSpec().isolationScope(IsolationScope.USER));
} else {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] In local mode, LocalFilesystemSpec defaults to LocalFsMode.ROOTED with project resolving to System.getProperty("user.dir"). For the builder context, consider explicitly setting .project(cwd) so the agent's shell pwd matches the builder's configured workspace root rather than the JVM working directory:

b.filesystem(new LocalFilesystemSpec()
    .project(cwd)
    .isolationScope(IsolationScope.USER));

This is non-blocking — the default works, but explicit is clearer.

@AgentScopeJavaBot AgentScopeJavaBot left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI Review

This PR fixes a genuine out-of-the-box startup failure where BuilderConfig unconditionally wired RemoteFilesystemSpec but fell back to InMemoryAgentStateStore when no distributed store was available — a combination HarnessAgent correctly rejects. The fix is clean and well-scoped: a new isLocalStateStore() helper detects local stores and switches to LocalFilesystemSpec, producing a consistent local-mode topology. The existing test (BuilderAppContextLoadTest) remains unaffected because its Mockito proxy is typed as AgentStateStore (not InMemoryAgentStateStore), so it still takes the RemoteFilesystemSpec path. One recommended improvement: the whitelist-based instanceof check is fragile — any future local AgentStateStore implementation will silently fall into the distributed branch and reproduce the original bug.

* {@link RemoteFilesystemSpec}.
*/
private static boolean isLocalStateStore(AgentStateStore store) {
return store instanceof InMemoryAgentStateStore || store instanceof JsonFileAgentStateStore;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[major] The whitelist-based detection (instanceof InMemoryAgentStateStore || instanceof JsonFileAgentStateStore) is fragile: if a new local AgentStateStore implementation is added (e.g. an embedded SQLite store), it will silently fall into the distributed branch and reproduce the exact topology-mismatch bug this PR fixes.

Consider either:

  1. Adding a marker interface or method on AgentStateStore itself, e.g. default boolean isDistributed() { return true; }, overridden to false by local implementations; or
  2. Inverting to a blacklist of known distributed stores:
private static boolean isLocalStateStore(AgentStateStore store) {
    return !(store instanceof MysqlAgentStateStore
            || store instanceof RedisAgentStateStore
            || store instanceof JedisAgentStateStore
            || store instanceof RedissonAgentStateStore
            || store instanceof OssAgentStateStore);
}

Option 1 is more robust and pushes the classification to where it belongs (the store contract). Option 2 is a quick improvement if changing the interface is out of scope for this PR.

.addSharedPrefix("activity/"));
if (localStore) {
b.filesystem(new LocalFilesystemSpec().isolationScope(IsolationScope.USER));
} else {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nit] In local mode, LocalFilesystemSpec defaults to LocalFsMode.ROOTED with project resolving to System.getProperty("user.dir"). For the builder context, consider explicitly setting .project(cwd) so the agent's shell pwd matches the builder's configured workspace root rather than the JVM working directory:

b.filesystem(new LocalFilesystemSpec()
    .project(cwd)
    .isolationScope(IsolationScope.USER));

This is non-blocking — the default works, but explicit is clearer.

@codecov

codecov Bot commented Jun 19, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@chickenlj chickenlj merged commit b27ca24 into agentscope-ai:main Jun 25, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/examples agentscope-examples bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: agentscope-builder fails to start out-of-the-box: RemoteFilesystemSpec rejected with InMemoryAgentStateStore fallback

3 participants