agentscope-ai / agentscope-ai/agentscope-java
Harness: public shell execution lifecycle provider (stream, cancel, cleanup, readback)
- Linguagem predominante
- Java
- Estrelas
- 5.6k
- Forks
- 1.3k
- Merge médio
- 4d 12h
- PRs com merge (30d)
- 77
Descrição
## 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.
Guia de contribuição
Avaliação
Esta issue ainda não foi avaliada.