Describe the bug
When an application modifies WORKSPACE_PROJECTION_ROOTS in SandboxFilesystemSpec (e.g., adding .skills-cache to the projection list), the change is ignored for existing sandboxes resumed from Redis. The sandbox continues using the old WorkspaceSpec persisted in SandboxState, even though the application layer has provided an updated configuration.
To Reproduce
-
Initial deployment — Application configures projection roots:
private static final List<String> WORKSPACE_PROJECTION_ROOTS =
List.of("AGENTS.md", "skills", "subagents", "knowledge");
new KubernetesFilesystemSpec()
.workspaceProjectionRoots(WORKSPACE_PROJECTION_ROOTS);
First run creates sandbox, SandboxState.workspaceSpec (containing the projection config) is persisted to Redis.
-
Configuration update — Add .skills-cache to projection roots:
private static final List<String> WORKSPACE_PROJECTION_ROOTS =
List.of("AGENTS.md", "skills", "subagents", "knowledge", ".skills-cache");
Redeploy the application.
-
Observe the issue — The .skills-cache directory exists on the host but is NOT projected into the sandbox.
-
Workaround — Delete the Redis cache (or manually call stateStore.delete(scopeKey)). The sandbox is recreated with the new configuration, and .skills-cache appears.
Expected behavior
When the application layer updates WORKSPACE_PROJECTION_ROOTS, the next sandbox resume should apply the updated configuration, not the stale config persisted in Redis.
Root cause
SandboxManager.acquire() (L101-108) deserializes SandboxState from Redis and directly passes it to client.resume(state). The WorkspaceSpec inside state was captured during the first create() call and is never updated.
Later, AbstractBaseSandbox.start() (L71) uses state.getWorkspaceSpec() — the stale spec from Redis — instead of the fresh spec from SandboxContext.
// SandboxManager.java L106-107
SandboxState state = client.deserializeState(stateJson.get());
Sandbox sandbox = client.resume(state); // ← state.workspaceSpec is stale
// AbstractBaseSandbox.java L71
WorkspaceSpec spec = state.getWorkspaceSpec(); // ← uses stale spec
Proposed fix
After deserializing SandboxState, overwrite state.workspaceSpec with the current sandboxContext.workspaceSpec:
// SandboxManager.java L106-109
SandboxState state = client.deserializeState(stateJson.get());
if (sandboxContext.getWorkspaceSpec() != null) {
state.setWorkspaceSpec(sandboxContext.getWorkspaceSpec().copy());
}
Sandbox sandbox = client.resume(state);
This ensures resumed sandboxes respect updated application configuration.
Environment
- AgentScope-Java Version: 2.0.0-SNAPSHOT (commit ddad83a)
- Java Version: 17
- OS: Windows 11
Additional context
This issue affects all WorkspaceSpec configuration changes:
- Workspace projection roots (the reported case)
- Environment variables
- Workspace entries
The current design prioritizes state persistence over configuration updates, which is counter-intuitive for application developers who expect configuration changes to take effect after redeployment.
Describe the bug
When an application modifies
WORKSPACE_PROJECTION_ROOTSinSandboxFilesystemSpec(e.g., adding.skills-cacheto the projection list), the change is ignored for existing sandboxes resumed from Redis. The sandbox continues using the oldWorkspaceSpecpersisted inSandboxState, even though the application layer has provided an updated configuration.To Reproduce
Initial deployment — Application configures projection roots:
First run creates sandbox,
SandboxState.workspaceSpec(containing the projection config) is persisted to Redis.Configuration update — Add
.skills-cacheto projection roots:Redeploy the application.
Observe the issue — The
.skills-cachedirectory exists on the host but is NOT projected into the sandbox.Workaround — Delete the Redis cache (or manually call
stateStore.delete(scopeKey)). The sandbox is recreated with the new configuration, and.skills-cacheappears.Expected behavior
When the application layer updates
WORKSPACE_PROJECTION_ROOTS, the next sandbox resume should apply the updated configuration, not the stale config persisted in Redis.Root cause
SandboxManager.acquire()(L101-108) deserializesSandboxStatefrom Redis and directly passes it toclient.resume(state). TheWorkspaceSpecinsidestatewas captured during the firstcreate()call and is never updated.Later,
AbstractBaseSandbox.start()(L71) usesstate.getWorkspaceSpec()— the stale spec from Redis — instead of the fresh spec fromSandboxContext.Proposed fix
After deserializing
SandboxState, overwritestate.workspaceSpecwith the currentsandboxContext.workspaceSpec:This ensures resumed sandboxes respect updated application configuration.
Environment
Additional context
This issue affects all
WorkspaceSpecconfiguration changes:The current design prioritizes state persistence over configuration updates, which is counter-intuitive for application developers who expect configuration changes to take effect after redeployment.