Fixes #5997, fixes #4081, fixes #4723, fixes #6625, fixes #3923 Refs #6606 — this PR removes the rejected root `paperclip` field, but #6606 also requires the protocol v3→v4 bump, which is out of scope here; referencing rather than closing it. ## Thinking Path > - Paperclip is the control plane that wakes and coordinates agent workers across company-scoped execution flows. > - The `openclaw_gateway` adapter is part of that wake path, so its outbound payload contract has to match the gateway's validated `agent` schema. > - `master` currently reintroduces a previously fixed regression by sending a top-level `paperclip` property in `agentParams` (see #3923, which reverts the original fix in #626). > - The gateway rejects unknown root params, which means OpenClaw wakes fail before the remote agent can start work. > - The actual wake context already rides in the generated `message`, so the extra root property is both redundant and harmful. > - This pull request removes that leaked root property, adds a focused regression test around param construction, and updates affected server expectations/docs to the supported contract. > - The benefit is that OpenClaw Gateway agents wake successfully again without losing inline wake context. ## What Changed - Removed the top-level `paperclip` field from OpenClaw Gateway `agentParams` and extracted `buildAgentParams()` so the contract is easy to test. - Added a package-level regression test that proves `payloadTemplate.paperclip` is stripped while explicit `agentId`/`timeout` behavior stays intact. - Updated server tests that inspect OpenClaw Gateway payloads to assert wake data is delivered in `message` instead of a rejected root field. - Updated the adapter configuration docs to state that wake context is embedded in the generated message text, not sent as a top-level param. ### Rebase onto current `master` (conflict resolution) This branch was opened against an older `master`; re-merging current `master` required: - Resolving conflicts in `execute.ts` — `master` hoisted `configuredAgentId` and moved the agentId/timeout precedence inline; this PR keeps the `buildAgentParams()` extraction that strips the gateway-rejected root `paperclip`. - Updating tests `master` added **after** this branch's base that assert the old root-`paperclip` contract. These suites use the OpenClaw gateway adapter purely as a delivery harness (`adapterType: "openclaw_gateway"` + a mock gateway) and observe wake content via the gateway payload, so dropping the root field requires them to read wake context from `message` instead: - `server/src/__tests__/heartbeat-comment-wake-batching.test.ts` - `server/src/__tests__/low-trust-red-team-routes.test.ts` (redaction guarantees preserved — sanitized body + `expectNoCanary` on the raw canary) - Replaced brittle JSON-substring assertions (flagged by Greptile) with a shared `parseWakePayloadFromMessage()` helper + `toMatchObject`, robust to serialization/key-order changes. The strict contract is confirmed upstream: OpenClaw's `AgentParamsSchema` is `Type.Object(..., { additionalProperties: false })` with no `paperclip` field, so a root `paperclip` is rejected (`invalid agent params: at root: unexpected property 'paperclip'`). ## Verification - `pnpm --filter @paperclipai/adapter-openclaw-gateway typecheck` — clean - `pnpm --filter @paperclipai/server typecheck` — clean - `pnpm exec vitest run --project @paperclipai/server server/src/__tests__/openclaw-gateway-adapter.test.ts server/src/__tests__/heartbeat-comment-wake-batching.test.ts server/src/__tests__/low-trust-red-team-routes.test.ts` — 26 passed (7 + 11 + 8) - `packages/adapters/openclaw-gateway/src/server/execute.test.ts` — 6 passed (run via a local temp vitest config because the root `vitest.config.ts` does not include this package) ## Risks - Low risk: this narrows the outbound payload to the gateway-supported contract and keeps wake context in the already-supported `message` channel. - Any downstream consumer that incorrectly depended on a top-level `paperclip` field from the gateway mock payloads would need to follow the supported `message` contract instead. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. Feature PRs that overlap with planned core work may need to be redirected — check the roadmap first. See `CONTRIBUTING.md`. ## Model Used - OpenAI Codex CLI coding agent via API authored the original change; exact underlying model ID and context window were not exposed in that environment. - Rebase/conflict resolution and the test-assertion migration were done with Claude Code (Claude Opus 4.8, 1M context). ## 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 the related issues above - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: serenakeyitan via breeze-runner <serenakeyitan@users.noreply.github.com> Co-authored-by: Andrew Aymeloglu <aaymeloglu@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| doc | ||
| src | ||
| CHANGELOG.md | ||
| README.md | ||
| package.json | ||
| tsconfig.json | ||
README.md
OpenClaw Gateway Adapter
This document describes how @paperclipai/adapter-openclaw-gateway invokes OpenClaw over the Gateway protocol.
Transport
This adapter always uses WebSocket gateway transport.
- URL must be
ws://orwss:// - Connect flow follows gateway protocol:
- receive
connect.challenge - send
req connect(protocol/client/auth/device payload) - send
req agent - wait for completion via
req agent.wait - stream
event agentframes into Paperclip logs/transcript parsing
Auth Modes
Gateway credentials can be provided in any of these ways:
authToken/tokenin adapter configheaders.x-openclaw-tokenheaders.x-openclaw-auth(legacy)password(shared password mode)
When a token is present and authorization header is missing, the adapter derives Authorization: Bearer <token>.
Device Auth
By default the adapter sends a signed device payload in connect params.
- set
disableDeviceAuth=trueto omit device signing - set
devicePrivateKeyPemto pin a stable signing key - without
devicePrivateKeyPem, the adapter generates an ephemeral Ed25519 keypair per run - when
autoPairOnFirstConnectis enabled (default), the adapter handles one initialpairing requiredby callingdevice.pair.list+device.pair.approveover shared auth, then retries once.
Session Strategy
The adapter supports the same session routing model as HTTP OpenClaw mode:
sessionKeyStrategy=issue|fixed|runsessionKeyis used when strategy isfixed
Resolved session key is sent as agent.sessionKey.
Payload Mapping
The agent request is built as:
- required fields:
message(wake text plus optionalpayloadTemplate.message/payloadTemplate.textprefix)idempotencyKey(PapercliprunId)sessionKey(resolved strategy)
- optional additions:
- all
payloadTemplatefields merged in agentIdfrom config if set and not already in template
- all
Timeouts
timeoutSeccontrols adapter-level request budgetwaitTimeoutMscontrolsagent.wait.timeoutMs
If agent.wait returns timeout, adapter returns openclaw_gateway_wait_timeout.
Log Format
Structured gateway event logs use:
[openclaw-gateway] ...for lifecycle/system logs[openclaw-gateway:event] run=<id> stream=<stream> data=<json>forevent agentframes
UI/CLI parsers consume these lines to render transcript updates.
No-remote-git contract
Like every Paperclip adapter, this one must treat the local execution-workspace
cwd as the only persistence boundary across runs — no git push from runtime
code, no assuming a git remote exists. The gateway transport here doesn't
touch the workspace directly, but if you extend the adapter to ship code to
the OpenClaw side, use the round-trip helpers in @paperclipai/adapter-utils
(prepareWorkspaceForSshExecution → restoreWorkspaceFromSshExecution)
rather than reaching for a git remote. See
packages/adapters/AUTHORING.md
for the full contract and the pinning test at
packages/adapter-utils/src/ssh-fixture.test.ts.