paperclip/packages/adapter-utils/src
Nicky Leach d1ba17eeca
fix(adapter-utils): fail fast when the sandbox control channel is lost mid-turn (#13158)
## Thinking Path

> - Paperclip is the open source app people use to manage AI agents for
work
> - Adapter utilities run agent turns and report their results to the
control plane
> - A lost sandbox control channel can leave an agent turn without a
result
> - The host then waits for the full adapter timeout instead of
reporting the loss
> - This pull request adds a push loss signal and a bounded host wait
> - The benefit is a prompt failure terminal when the agent stops
answering

## Linked Issues or Issue Description

**What happened?**

A sandbox control channel loss during an Agent Client Protocol turn left
the host waiting for the four-hour adapter execution timeout.

**Expected behavior**

The host should detect the terminal channel loss, stop the turn, and
report a safe failure without waiting for the agent.

**Steps to reproduce**

1. Start an Agent Client Protocol turn through a sandbox adapter.
2. Close the duplex control channel while the turn remains active.
3. Observe the host response before the adapter timeout expires.

**Paperclip version or commit**

Test the pull request commit set at
`10b6bbc5525a79fd575298607dd5a25ae448fc8a`.

**Deployment mode**

The change applies to sandbox-backed adapter execution.

## What Changed

- Add `onLoss(listener)` to the duplex bridge handle.
- Register the loss listener at turn start and read losses latched
before turn start.
- Cancel the turn on loss and arm a 30-second host deadline.
- Close the stream locally when the deadline wins and create a host
terminal.
- Derive the public error from the closed `DuplexLossReason` enum.
- Add tests for loss order, cancellation, timeout, and safe error
output.

## Verification

- Run `pnpm --filter @paperclipai/adapter-utils exec tsc --noEmit`.
- Run `pnpm --filter @paperclipai/adapter-utils exec vitest run
src/acpx-engine/execute.test.ts -t "run-disposition seam"`.
- Confirm that the full pull request workflow passes.

## Risks

The new deadline changes a lost-channel path from a long wait to a
host-built failure after 30 seconds. Orderly completion keeps its
existing behavior. The deadline race against a pending `turn.result` has
no direct test.

## Model Used

OpenAI Codex, GPT-5, with tool use and code execution. The runtime does
not expose a more specific deployment version or context-window size.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` /
`Closes: #` / `Refs: #` OR (b) described the issue in-PR following the
relevant issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-09-10 15:37:05 -07:00
..
acpx-engine fix(adapter-utils): fail fast when the sandbox control channel is lost mid-turn (#13158) 2026-09-10 15:37:05 -07:00
test-support feat(mcp) [split 4/8]: wire gateway runtime and Smoke Lab (#9559) 2026-07-14 15:07:30 -05:00
billing.test.ts feat(costs): add billing, quota, and budget control plane 2026-03-16 15:11:01 -05:00
billing.ts feat(costs): add billing, quota, and budget control plane 2026-03-16 15:11:01 -05:00
bridge-transport-contract.ts refactor(adapter-utils): remove the retired duplex_v1 sandbox bridge transport (#12171) 2026-08-25 08:47:43 -07:00
chat-file-delivery.test.ts feat: add experimental native chat connectors (#13038) 2026-09-10 10:06:45 -05:00
chat-file-delivery.ts feat: add experimental native chat connectors (#13038) 2026-09-10 10:06:45 -05:00
command-managed-runtime.test.ts Write mode-constrained inbound files directly to their target (#12320) 2026-08-27 10:54:11 -07:00
command-managed-runtime.ts fix(runner): persist warm Daytona workspaces (#12901) 2026-09-05 13:00:57 -05:00
command-redaction.test.ts fix(runner): restore local session and task integrity (#12721) 2026-09-02 16:11:26 -05:00
command-redaction.ts fix(runner): restore local session and task integrity (#12721) 2026-09-02 16:11:26 -05:00
duplex-frame-codec.test.ts refactor(adapter-utils): delete the dead duplex body-chunk protocol code (#12186) 2026-08-25 14:33:38 -07:00
duplex-frame-codec.ts refactor(adapter-utils): replace the process-wide byte ledger with route-local byte bounds (#12465) 2026-08-28 14:36:18 -07:00
duplex-frame-vectors.json refactor(adapter-utils): replace the process-wide byte ledger with route-local byte bounds (#12465) 2026-08-28 14:36:18 -07:00
duplex-observability.test.ts feat(duplex): run the Daytona sandbox callback bridge over Node HTTP/2 (#12120) 2026-08-25 07:35:39 -07:00
duplex-observability.ts refactor(adapter-utils): replace the process-wide byte ledger with route-local byte bounds (#12465) 2026-08-28 14:36:18 -07:00
env-bindings.test.ts fix(adapters): keep user-scoped env bindings on the agent Test action (#10926) 2026-08-05 17:18:41 -07:00
env-bindings.ts fix(adapters): keep user-scoped env bindings on the agent Test action (#10926) 2026-08-05 17:18:41 -07:00
exclude-patterns.ts Fix sandbox git publishing and large workspace uploads (#8422) 2026-06-20 22:03:55 -07:00
execution-target-sandbox.test.ts feat(adapter-utils): carry binary bodies and attachment routes over the HTTP/2 sandbox bridge (#12923) 2026-09-08 14:18:12 -07:00
execution-target-stdin-race.test.ts fix(adapter-utils): allow process sessions without birthtime (#12451) 2026-08-28 10:33:22 -07:00
execution-target.test.ts feat: use the responsible person's GitHub for shared agent operations (#13005) 2026-09-07 14:32:20 -05:00
execution-target.ts fix(adapter-utils): fail fast when the sandbox control channel is lost mid-turn (#13158) 2026-09-10 15:37:05 -07:00
git-workspace-sync.test.ts fix(adapter-utils): harden the referenced-project ignore scan (#12214) 2026-08-26 08:30:42 -07:00
git-workspace-sync.ts fix(adapter-utils): harden the referenced-project ignore scan (#12214) 2026-08-26 08:30:42 -07:00
github-launcher-environment.test.ts fix(adapters): probe Git context in the remote workspace (#13116) 2026-09-09 16:52:11 -05:00
github-launcher.test.ts fix(runner): restore legacy Git access and independent networking (#13094) 2026-09-09 10:15:10 -05:00
github-launcher.ts fix(runner): restore legacy Git access and independent networking (#13094) 2026-09-09 10:15:10 -05:00
http2-bridge-server.test.ts feat(adapter-utils): carry binary bodies and attachment routes over the HTTP/2 sandbox bridge (#12923) 2026-09-08 14:18:12 -07:00
http2-bridge-server.ts feat(adapter-utils): carry binary bodies and attachment routes over the HTTP/2 sandbox bridge (#12923) 2026-09-08 14:18:12 -07:00
index.ts fix: repair runner configuration, macOS execution, and artifact galleries (#13062) 2026-09-08 19:10:09 -05:00
local-process-sandbox.test.ts feat: use the responsible person's GitHub for shared agent operations (#13005) 2026-09-07 14:32:20 -05:00
local-process-sandbox.ts fix(adapter-utils): keep sandbox proxy sockets within Linux path limit (#10221) 2026-07-26 10:52:16 -05:00
log-redaction.ts fix(ui): external adapter selection, config field placement, and transcript parser freshness 2026-04-03 21:11:22 +01:00
login-capability.test.ts feat(login): use the login pseudo-terminal for Codex device login and de-Claude the shared channel (#12020) 2026-08-23 09:44:59 -07:00
login-capability.ts feat(login): use the login pseudo-terminal for Codex device login and de-Claude the shared channel (#12020) 2026-08-23 09:44:59 -07:00
login-pty-transport.test.ts feat(login): use the login pseudo-terminal for Codex device login and de-Claude the shared channel (#12020) 2026-08-23 09:44:59 -07:00
login-pty-transport.ts feat(login): use the login pseudo-terminal for Codex device login and de-Claude the shared channel (#12020) 2026-08-23 09:44:59 -07:00
login-runner-lifecycle.test.ts feat(auth): normalize agent login in the sandbox onto one session table and a capability contract (#11730) 2026-08-19 11:51:31 -07:00
login-runner-lifecycle.ts feat(auth): normalize agent login in the sandbox onto one session table and a capability contract (#11730) 2026-08-19 11:51:31 -07:00
mcp-isolation.integration.test.ts feat(skills): import skills from projects (#9620) 2026-07-15 18:01:44 -05:00
paperclip-runner-permissions.test.ts fix(runner): restore local session and task integrity (#12721) 2026-09-02 16:11:26 -05:00
paperclip-runner-permissions.ts fix: repair runner configuration, macOS execution, and artifact galleries (#13062) 2026-09-08 19:10:09 -05:00
published-exports.test.ts refactor: disambiguate the Telemetry and Observability data paths (#12128) 2026-08-24 16:42:33 -07:00
remote-execution-env.ts Sanitize remote execution envs at the boundary (#5325) 2026-05-05 19:30:14 -07:00
remote-managed-runtime.test.ts fix(adapter-utils): harden the referenced-project ignore scan (#12214) 2026-08-26 08:30:42 -07:00
remote-managed-runtime.ts fix(adapter-utils): honor .gitignore for referenced-project staging (#12184) 2026-08-25 14:22:47 -07:00
runner-connectivity.test.ts Unify Paperclip Runner experimental controls (#12666) 2026-09-01 09:21:23 -05:00
runner-connectivity.ts Unify Paperclip Runner experimental controls (#12666) 2026-09-01 09:21:23 -05:00
runtime-progress.test.ts feat(environments): refer to the managed default environment by name, not the sandbox driver key (#11838) 2026-08-21 12:51:22 -07:00
runtime-progress.ts feat(environments): refer to the managed default environment by name, not the sandbox driver key (#11838) 2026-08-21 12:51:22 -07:00
sandbox-callback-bridge.test.ts feat(adapter-utils): carry binary bodies and attachment routes over the HTTP/2 sandbox bridge (#12923) 2026-09-08 14:18:12 -07:00
sandbox-callback-bridge.ts feat(adapter-utils): carry binary bodies and attachment routes over the HTTP/2 sandbox bridge (#12923) 2026-09-08 14:18:12 -07:00
sandbox-file-sync.test.ts fix(adapter-utils): honor .gitignore for referenced-project staging (#12184) 2026-08-25 14:22:47 -07:00
sandbox-install-command.test.ts fix(build): enforce Node 24 across Paperclip (#11792) 2026-08-21 10:17:52 -07:00
sandbox-install-command.ts fix(build): enforce Node 24 across Paperclip (#11792) 2026-08-21 10:17:52 -07:00
sandbox-managed-runtime.test.ts fix(runner): persist warm Daytona workspaces (#12901) 2026-09-05 13:00:57 -05:00
sandbox-managed-runtime.ts fix(runner): persist warm Daytona workspaces (#12901) 2026-09-05 13:00:57 -05:00
sandbox-run-log-stream.ts Improve live agent feedback during sandboxed runs (#8915) 2026-07-02 22:21:56 -07:00
sandbox-shell.ts Add secrets provider vaults and remote import (#5429) 2026-05-09 18:22:17 -05:00
server-utils-env.test.ts fix: preserve control plane access in Codex sandbox (#10152) 2026-07-24 15:25:59 -05:00
server-utils.test.ts feat: add experimental native chat connectors (#13038) 2026-09-10 10:06:45 -05:00
server-utils.ts feat: add experimental native chat connectors (#13038) 2026-09-10 10:06:45 -05:00
session-compaction.ts feat: add kimi-local adapter for Kimi Code CLI (CLI + ACP engines) (#9967) 2026-08-20 12:06:33 -07:00
skill-library-manifest.test.ts feat: agents see the company skill library at runtime (#12147) 2026-08-25 14:01:52 -07:00
skill-library-manifest.ts feat: agents see the company skill library at runtime (#12147) 2026-08-25 14:01:52 -07:00
ssh-fixture.test.ts fix(adapter-utils): make SSH env-lab fixture teardown deterministic (#12238) 2026-08-26 14:03:47 -07:00
ssh.ts fix(adapter-utils): make SSH env-lab fixture teardown deterministic (#12238) 2026-08-26 14:03:47 -07:00
sync-operation-schedule.test.ts feat: parallelize sandbox file-sync behind a provider opt-in capability (#11736) 2026-08-19 12:34:11 -07:00
sync-operation-schedule.ts feat: parallelize sandbox file-sync behind a provider opt-in capability (#11736) 2026-08-19 12:34:11 -07:00
types.ts feat: add experimental native chat connectors (#13038) 2026-09-10 10:06:45 -05:00
workspace-restore-merge.test.ts fix(runner): persist warm Daytona workspaces (#12901) 2026-09-05 13:00:57 -05:00
workspace-restore-merge.ts fix(runner): persist warm Daytona workspaces (#12901) 2026-09-05 13:00:57 -05:00
workspace-restore-teardown.test.ts refactor(adapter-utils): extract the shared workspace-restore teardown factory (#12196) 2026-08-25 21:38:27 -07:00
workspace-restore-teardown.ts refactor(adapter-utils): extract the shared workspace-restore teardown factory (#12196) 2026-08-25 21:38:27 -07:00