agentscope-ai / agentscope-ai/agentscope-java

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

未關閉
#1,632 1 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視
area/harness bug
主要語言
Java
星號
5.6k
分支
1.3k
平均合併
4 天 12 小時
30 天內合併 PR
77

描述

**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.

貢獻指南

開啟貢獻指南

評估

這個 Issue 還沒有評估資料。

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。