agentscope-ai / agentscope-ai/agentscope-java

Harness: public shell execution lifecycle provider (stream, cancel, cleanup, readback)

Ouverte
#2,138 2 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
area/harness enhancement
Langage dominant
Java
Étoiles
5.6k
Forks
1.3k
Merge moyen
4 j 12 h
PR mergées (30 j)
77

Description

## Motivation

AgentScope Harness currently exposes shell execution only as:

```java
ExecuteResponse execute(RuntimeContext context, String command, Integer timeoutSeconds)
```

This synchronous aggregate contract cannot represent execution identity, ordered stdout/stderr chunks, explicit cancellation, background status, process/container cleanup, or restart readback. `AsyncToolMiddleware` is not an execution lifecycle substitute: it offloads an arbitrary tool invocation and explicitly lets the underlying execution continue (`never cancelled`). `TaskRepository` is scoped to subagent tasks and should not become a shell process registry.

The immediate pipe deadlock remains tracked separately in #1519. This proposal is for the product-grade lifecycle after/alongside that focused fix.

Observed against `e3a412ed2cc944e401da861c8d5e464b967724e9`.

## Proposed public contract

Introduce a Harness-owned execution provider SPI, conceptually:

```java
interface ExecutionProvider {
ExecutionHandle start(RuntimeContext context, ExecutionRequest request);
Optional get(RuntimeContext context, String executionId);
ExecutionSnapshot cancel(RuntimeContext context, String executionId);
Flux stream(RuntimeContext context, String executionId, long afterSequence);
}
```

The exact API can differ, but the behavior should include:

- stable `executionId` scoped by tenant/user/session/workspace;
- monotonically sequenced stdout/stderr chunks with bounded retention/truncation facts;
- typed states such as `STARTING/RUNNING/COMPLETED/FAILED/TIMED_OUT/CANCELLED`;
- exactly one terminal transition;
- idempotent cancel;
- direct process plus descendant process-tree cleanup for local execution, and equivalent container/job cleanup for sandbox providers;
- explicit cwd/environment/shell identity derived from the Harness workspace/filesystem policy;
- reconnect/readback after subscriber loss, and a declared capability when restart recovery is unsupported;
- permission/HITL remains before `start`, with no alternate execution path bypassing `PermissionEngine`;
- typed events suitable for `streamEvents()`/OTel without requiring a product host process table.

`ShellExecuteTool` could keep the current aggregate response as a compatibility adapter over the provider, while a lifecycle-aware tool/API uses the typed handle directly.

## Provider ownership and possible implementations

The SPI and lifecycle state should be owned by Harness/sandbox implementations, not by each product host.

- Local provider: JDK `ProcessBuilder` + concurrent bounded drains + `ProcessHandle.descendants()`; Apache Commons Exec could help watchdog/stream pumping but does not define durable identity/readback.
- Interactive optional provider: pty4j/ConPTY, advertised as a separate PTY capability rather than required for non-interactive commands.
- Docker/Kubernetes/cloud sandbox providers: map the same handle/events to container exec/job primitives and their native cleanup/status APIs.

A third-party library can implement a provider, but directly adding it to an application host would create a second shell/process runtime and produce different behavior from Docker/Kubernetes backends.

## Acceptance cases

1. 30K/90K stdout, stderr-only and mixed output complete without pipe deadlock and with bounded retention.
2. Slow streaming output is ordered and resumable from a sequence cursor.
3. Timeout and cancel terminate descendants and produce one terminal state.
4. Cancel is idempotent and races safely with natural completion.
5. Disconnect/reconnect reads the same execution state; restart support is either proven or fail-closed by capability.
6. USER/SESSION workspace namespace and cwd isolation are preserved.
7. Local and sandbox implementations expose the same lifecycle semantics.
8. A product host needs no `ProcessBuilder`, process map, polling scheduler, or shell result store.

## Relationship to existing components

- #1519 should remain a small concurrent-drain bug fix and need not wait for this SPI.
- `AsyncToolMiddleware` can observe/offload a lifecycle-aware tool, but should not own or hide cancellation.
- `TaskRepository` remains the subagent task owner unless Harness intentionally introduces a common, typed job substrate with distinct task kinds and recovery semantics.

Guide de contribution

Ouvrir le guide de contribution

Évaluation

Cette issue n'a pas encore été évaluée.

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.