Skip to content
Open
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 @@ -16,6 +16,8 @@
package io.agentscope.harness.agent.sandbox;

import io.agentscope.core.agent.RuntimeContext;
import io.agentscope.harness.agent.sandbox.snapshot.RemoteSandboxSnapshot;
import io.agentscope.harness.agent.sandbox.snapshot.SandboxSnapshot;
import java.util.Objects;
import java.util.Optional;
import org.slf4j.Logger;
Expand Down Expand Up @@ -103,6 +105,7 @@ public SandboxAcquireResult acquire(
"[sandbox] Priority 3: resuming from persisted state (scope={})",
scopeKey.get());
SandboxState state = client.deserializeState(stateJson.get());
reInjectRemoteSnapshot(state, sandboxContext);
Sandbox sandbox = client.resume(state);
return SandboxAcquireResult.selfManaged(sandbox, lease);
}
Expand Down Expand Up @@ -225,4 +228,24 @@ public void clearState(SandboxContext sandboxContext, RuntimeContext runtimeCont
log.warn("[sandbox] Failed to clear sandbox state: {}", e.getMessage(), e);
}
}

/**
* Re-wires a deserialized {@link RemoteSandboxSnapshot} with a live
* {@link io.agentscope.harness.agent.sandbox.snapshot.RemoteSnapshotClient} from the
* {@link SandboxContext#getSnapshotSpec()}.
*
* <p>After JSON deserialization, {@code RemoteSandboxSnapshot} has only the {@code id}
* — the {@code RemoteSnapshotClient} must be re-injected before any I/O operations
* (snapshot restore during sandbox start).
*/
private void reInjectRemoteSnapshot(SandboxState state, SandboxContext sandboxContext) {
SandboxSnapshot snapshot = state.getSnapshot();
if (snapshot instanceof RemoteSandboxSnapshot && sandboxContext.getSnapshotSpec() != null) {
SandboxSnapshot rewired = sandboxContext.getSnapshotSpec().build(snapshot.getId());
state.setSnapshot(rewired);
log.debug(
"[sandbox] Re-wired RemoteSandboxSnapshot client for snapshot id={}",
snapshot.getId());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
*/
package io.agentscope.harness.agent.sandbox.snapshot;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.agentscope.harness.agent.sandbox.SandboxException;
import java.io.InputStream;

Expand All @@ -28,16 +32,22 @@
* {@link RemoteSnapshotClient} cannot be serialized. When persisting session state,
* only the {@code id} is needed — the client is re-injected from the builder at resume time.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class RemoteSandboxSnapshot implements SandboxSnapshot {

private final RemoteSnapshotClient client;
@JsonIgnore private final RemoteSnapshotClient client;
private final String id;

@JsonCreator
private RemoteSandboxSnapshot(@JsonProperty("id") String id) {
this.id = id;
this.client = null;
}

/**
* Creates a remote snapshot.
*
* @param client the remote storage client to delegate operations to
* @param id unique identifier for this snapshot
* @param id unique identifier for this snapshot
*/
public RemoteSandboxSnapshot(RemoteSnapshotClient client, String id) {
this.client = client;
Expand Down Expand Up @@ -78,6 +88,7 @@ public InputStream restore() throws Exception {
* <p>Checks existence via {@link RemoteSnapshotClient#exists}.
*/
@Override
@JsonIgnore
public boolean isRestorable() throws Exception {
try {
return client.exists(id);
Expand All @@ -92,6 +103,7 @@ public String getId() {
}

@Override
@JsonIgnore
public String getType() {
return "remote";
}
Expand Down
Loading