agentscope-ai / agentscope-ai/agentscope-java

[Bug]: agentscope-dataagent — per-user workspace not persisted single-node (UserSandboxRegistry hardcodes NoopSnapshotSpec, bypasses snapshot persist/restore)

Abierto
#1,632 1 comentario 0 reacciones 0 asignados Ver en GitHub
area/harness bug
Lenguaje dominante
Java
Estrellas
5.6k
Forks
1.3k
Merge medio
4 d 12 h
PR fusionados (30 d)
77

Descripción

**Describe the bug**

In a single-node `agentscope-dataagent` deployment, **per-user workspace state is never persisted**: anything a user's agent writes into its workspace — created skills, session transcripts, `memory/` — is lost when the per-user sandbox is idle-evicted (default 15 min) or when the app restarts. Only the H2 catalog (accounts, agents, contributions) and the read-only `shared/` content survive.

This happens even though the harness ships a full snapshot subsystem (`LocalSnapshotSpec`, `OssSnapshotSpec`, `RedisSnapshotSpec`, `RemoteSnapshotSpec`) that is designed to persist/restore a sandbox workspace. The DataAgent single-node path never reaches it:

1. `UserSandboxRegistry` creates every per-`(userId, agentId)` sandbox with a **hardcoded** `NoopSnapshotSpec`:
`UserSandboxRegistry.java:234` — `Sandbox sandbox = client.create(ws, new NoopSnapshotSpec(), options);`
2. Even if a real snapshot spec were passed, `DockerSandboxClient.create()` keys the snapshot by a **random** id:
`DockerSandboxClient.java:63` — `String sessionId = UUID.randomUUID().toString();`
so a snapshot saved on stop could never be matched/restored on the next `create` after a restart.
3. The registry's sandbox is injected as an **external sandbox** (`SandboxContext.getExternalSandbox()`, Priority-1 acquire — `HarnessGateway` ~:496), which **bypasses `SandboxManager`'s snapshot persist/restore flow** entirely. So the snapshot machinery is never invoked for the workspace users actually read/write.

Net effect: the snapshot specs (incl. local-disk and OSS) cannot be used to persist the per-user workspace in the single-node `UserSandboxRegistry` path, regardless of configuration.

**To Reproduce**

1. Run the app single-node (default; needs the #1600 startup fixes to boot).
2. Log in, send a chat message (a per-user `ubuntu:22.04` sandbox starts), let the agent create/modify a skill or accumulate session history.
3. Restart the app (or wait for the 15-min idle eviction), then log in again as the same user.
4. The previously created skill / session transcript / memory is gone — the new sandbox starts from only the projected `shared/` seed.

**Expected behavior**

Per-user workspace state should be persistable across sandbox idle-eviction and app restarts in single-node mode — e.g. by wiring one of the existing snapshot backends (`LocalSnapshotSpec` for disk, `OssSnapshotSpec` for object storage) into `UserSandboxRegistry` with a **stable** per-`(userId, agentId)` key, or by bind-mounting a host/volume directory into each sandbox's `/workspace`.

**Error messages**

No error — silent data loss. (Reading a stale session after eviction returns empty content; see also #1626.)

**Environment (please complete the following information):**

- AgentScope-Java Version: 2.0.0-RC1 (identical to `main` for this module)
- Java Version: 17
- OS: macOS (arm64), Docker (DooD, host socket mounted)

**Additional context**

- The README implies per-user persistence ("each user has their own private workspace … whatever memory their agent builds up — it stays theirs"), and the config exposes `dataagent.sandbox.idle-ttl-min` (default 15, `DataAgentWorkspaceConfig.java:55`) which silently discards workspace state on eviction. There is no persistence path behind it for the workspace itself.
- The harness snapshot subsystem already exists and works via `SandboxManager` (create with a real `SandboxSnapshotSpec` → `snapshot.persist()` on stop / `snapshot.restore()` on start). The gap is purely that DataAgent's `UserSandboxRegistry` external-sandbox path neither passes a real spec nor uses a stable key nor routes through that flow.

Suggested directions:
- Give `UserSandboxRegistry` a configurable `SandboxSnapshotSpec` (e.g. `LocalSnapshotSpec()` / `OssSnapshotSpec(...)`) and a **stable snapshot id** per `(userId, agentId)`, and persist/restore on borrow/evict; or
- Add an optional per-`(userId, agentId)` bind-mount (`WorkspaceSpec` / `BindMountEntry`) so `/workspace` is backed by a host/volume directory directly.

Related: #1600 (startup), #1626 (session-read out-of-band) — same sandbox-backed-workspace architecture.

Guía de contribución

Abrir la guía de contribución

Evaluación

Este issue todavía no se ha evaluado.

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.