Skip to content

feat(gateway): accept opaque paperclip envelope on agent params#75901

Closed
bzanghi wants to merge 1 commit into
openclaw:mainfrom
bzanghi:feat/agent-params-accept-paperclip-envelope
Closed

feat(gateway): accept opaque paperclip envelope on agent params#75901
bzanghi wants to merge 1 commit into
openclaw:mainfrom
bzanghi:feat/agent-params-accept-paperclip-envelope

Conversation

@bzanghi

@bzanghi bzanghi commented May 2, 2026

Copy link
Copy Markdown

Problem

External orchestrators (today: Paperclip's @paperclipai/adapter-openclaw-gateway) attach an opaque paperclip envelope at the root of every agent request — runId, taskId, wakeReason, workspace, etc., used for upstream observability and future correlation.

AgentParamsSchema is declared with additionalProperties: false, so the gateway rejects the entire wake with:

INVALID_REQUEST: invalid agent params: at root: unexpected property 'paperclip'

This blocks every Paperclip → OpenClaw heartbeat. Today users work around it by hot-patching the installed protocol-Hjar_s3V.js after every brew upgrade openclaw.

Fix

Declare paperclip: Type.Optional(Type.Unknown()) on AgentParamsSchema so the field is accepted and silently ignored. The gateway code never reads it (no paperclip references anywhere under src/gateway/server-methods/), so this is a pure pass-through.

additionalProperties: false stays in place — this only opens a single named, well-understood field, not a wildcard.

This mirrors the forward-compat stance already taken by WakeParamsSchema (additionalProperties: true) and the existing test that validates paperclip on wake params (src/gateway/protocol/index.test.ts line 167).

Tests

Added three validateAgentParams cases:

  • minimal valid agent request
  • agent request with the new paperclip envelope
  • still rejects other unknown root fields (regression guard)
pnpm exec vitest run src/gateway/protocol/index.test.ts
  → Tests  42 passed (42)

pnpm exec vitest run src/gateway/server-methods/agent.test.ts
  → Tests  164 passed (164)

AI-assisted disclosure

  • AI-assisted (Claude Code, Opus 4.7)
  • Fully tested (targeted vitest specs above)
  • I understand what the code does — schema-only addition; no behavior change in the gateway
  • Codex review not run locally; relying on PR CI

External orchestrators (currently Paperclip's `openclaw_gateway`
adapter) attach an opaque `paperclip` envelope at the root of every
`agent` request. The gateway never reads the field, but the strict
`AgentParamsSchema` (`additionalProperties: false`) was rejecting the
whole request with `at root: unexpected property 'paperclip'`,
blocking every wake.

Declare `paperclip: Type.Optional(Type.Unknown())` so the field is
accepted (and ignored) without weakening strictness for any other
unknown field. Mirrors the forward-compat stance already taken by
`WakeParamsSchema` (`additionalProperties: true`).

Adds three `validateAgentParams` tests covering the minimal shape,
the new envelope, and that other unknown root fields still fail.

AI-assisted (Claude Code), fully tested locally:
- pnpm exec vitest run src/gateway/protocol/index.test.ts (42 passed)
- pnpm exec vitest run src/gateway/server-methods/agent.test.ts (164 passed)
@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui gateway Gateway runtime size: XS labels May 2, 2026
@clawsweeper

clawsweeper Bot commented May 2, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

Close as duplicate/superseded. The Paperclip paperclip rejection is real on current main, but #74974 already tracks the same remaining Gateway protocol change; this branch is a narrower duplicate and also omits required generated protocol artifacts and changelog coverage.

So I’m closing this here and keeping the remaining discussion on the canonical linked item.

Review details

Best possible solution:

Consolidate review on #74974 or the underlying Paperclip report, then land one approved Gateway protocol change with schema, generated client artifacts, tests, and changelog synchronized.

Do we have a high-confidence way to reproduce the issue?

Yes. A Gateway agent request with required message and idempotencyKey plus a root paperclip field follows the current validateAgentParams failure path because AgentParamsSchema is closed and has no such field.

Is this the best way to solve the issue?

No for this PR as the merge vehicle. The schema tolerance may be the narrow mechanical fix, but this branch duplicates #74974 and omits generated protocol model and changelog updates required for a complete Gateway protocol change.

Security review:

Security review cleared: The diff widens validation for one ignored opaque field and adds tests, with no CI, dependency, credential, code execution, or supply-chain surface changed.

What I checked:

Likely related people:

  • steipete: Current blame and recent history for AgentParamsSchema, the agent validation path, and protocol artifact alignment are dominated by Peter Steinberger commits, making this the most likely maintainer route for the public Gateway schema decision. (role: protocol owner / recent maintainer; confidence: high; commits: d85d782a0a27, a448042c2edd, 903f771c9372; files: src/gateway/protocol/schema/agent.ts, src/gateway/server-methods/agent.ts, apps/macos/Sources/OpenClawProtocol/GatewayModels.swift)
  • kagura-agent: The Paperclip argument cites the existing WakeParamsSchema forward-compatibility behavior; the relevant history shows the WakeParams unknown-property change came from this author. (role: adjacent protocol precedent author; confidence: medium; commits: 2c3542e31514; files: src/gateway/protocol/schema/agent.ts, src/gateway/protocol/index.test.ts)
  • vincentkoc: Recent gateway/protocol history includes type-surface and shared-consumer refactors by Vincent Koc near the same public contract area, though not the exact AgentParamsSchema line. (role: adjacent Gateway/protocol maintainer; confidence: low; commits: f630e8d44037, 74e7b8d47b18; files: src/gateway/protocol, src/gateway/server-methods/agent.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against d2f623d5604c.

@clawsweeper clawsweeper Bot closed this May 2, 2026
jeffrey701 added a commit to jeffrey701/openclaw that referenced this pull request May 8, 2026
…tadata

The first commit on this branch added `paperclip: Type.Optional(Type.Unknown())`
to AgentParamsSchema as a vendor-named root-level tolerance field. The
review on openclaw#74974 (and the surrounding history of openclaw#62102, openclaw#74635, openclaw#72565,
openclaw#69139, openclaw#75901 — three earlier PRs proposing the same vendor-named
shape, all closed without merge) makes the underlying request clear:
the right contract is a generic opaque-metadata namespace any external
agent or plugin adapter can write under, not a name-per-vendor field
that grows the gateway protocol surface every time a new adapter ships.

This commit lands that namespace alongside the existing alias:

- AgentParamsSchema gains `adapterMeta: Type.Optional(Type.Record(
  Type.String(), Type.Unknown()))`. Each adapter writes its own top-level
  key under it (`adapterMeta: { paperclip: {...}, greptile: {...} }`); the
  gateway accepts the bag as opaque and never inspects it.
- The existing `paperclip: Type.Optional(Type.Unknown())` field is kept
  as a backward-compatibility alias, with a comment documenting that new
  adapter metadata should use `adapterMeta` and that this field can be
  removed once the published Paperclip adapter cuts a release that nests
  its payload under `adapterMeta.paperclip`. Heartbeats from current
  Paperclip releases keep dispatching during the transition.
- `additionalProperties: false` on AgentParamsSchema is left intact, so
  a typo'd root field (e.g. `idempotnecyKey`) still fails validation
  before dispatch — the fix doesn't widen the schema, it just adds two
  named landing pads.

Tests in src/gateway/protocol/agent-params-validator.test.ts now cover:

- adapterMeta with multiple adapter keys (paperclip + greptile) accepted
- empty adapterMeta and adapterMeta with primitive values accepted
- both surfaces side by side (paperclip + adapterMeta.paperclip) accepted
- adapterMeta with a non-object value rejected
- existing paperclip-only path unchanged
- truly unknown root properties still rejected
- canonical message + idempotencyKey still required

Swift bindings in apps/shared/OpenClawKit/Sources/OpenClawProtocol/
GatewayModels.swift mirror the new field as `adaptermeta: [String:
AnyCodable]?` in the four codegen sites (declaration, init signature,
init body, CodingKeys = "adapterMeta"), matching the pattern used for
`inputprovenance` and the existing `paperclip` mirror.

CHANGELOG.md gets a `Gateway/protocol:` entry under `## Unreleased`
describing the namespace + alias and citing openclaw#74635 and openclaw#62102 as the
issues being closed.

Refs openclaw#74974, openclaw#74635, openclaw#62102
jeffrey701 added a commit to jeffrey701/openclaw that referenced this pull request May 8, 2026
… alias on AgentParamsSchema

Paperclip and other external agents inject a root-level metadata blob
when invoking agents via the openclaw_gateway adapter, but
AgentParamsSchema is declared with additionalProperties: false so the
gateway rejects the entire payload before dispatch:

    invalid agent params: at root: unexpected property 'paperclip'

Reported by openclaw#74635 (Paperclip rev 3494e84 vs OpenClaw 2026.4.26
be8c246) and openclaw#62102. Three earlier PRs proposed a vendor-named root
field (openclaw#69139, openclaw#72565, openclaw#75901) - all closed without merge - so this
lands the fix as a generic namespace plus a backward-compatibility
alias instead.

Schema (src/gateway/protocol/schema/agent.ts)

- AgentParamsSchema gains 'adapterMeta: Type.Optional(Type.Record(
  Type.String(), Type.Unknown()))'. Each external agent or plugin
  adapter writes under its own top-level key here
  (adapterMeta: { paperclip: {...}, greptile: {...} }); the gateway
  accepts the bag as-is and never inspects it. New adapters can land
  protocol-side without growing the schema.
- AgentParamsSchema also gains 'paperclip: Type.Optional(Type.Unknown())'
  as a backward-compatibility alias, with a comment marking it for
  removal once the published Paperclip adapter cuts a release that
  nests under adapterMeta.paperclip. Heartbeats from current Paperclip
  releases keep dispatching during the transition.
- additionalProperties: false on AgentParamsSchema is intentionally
  untouched. Truly unknown root fields (e.g. typo'd 'idempotnecyKey')
  still fail validation before dispatch.

Swift bindings (apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift)

Mirror the two new fields on the AgentParams struct in all four
codegen positions (declaration, init signature, init body, CodingKeys),
following the existing 'inputprovenance' and 'cleanupbundlemcponrunend'
pattern:

    public let adaptermeta: [String: AnyCodable]?
    public let paperclip: AnyCodable?

The macOS-side mirror was deleted upstream so only the shared one needs
to be regenerated.

Tests (src/gateway/protocol/agent-params-validator.test.ts, new)

- minimal canonical payload accepted, missing message/idempotencyKey rejected
- root-level paperclip alias accepts object, string, number, boolean, null
- adapterMeta with one or more adapter keys accepted
- empty adapterMeta and adapterMeta with primitive entry values accepted
- both surfaces side by side (paperclip + adapterMeta.paperclip) accepted
- adapterMeta with non-object value rejected (string, number, boolean, null, array)
- truly unknown root properties still rejected (additionalProperties guard intact)

Verification

- pnpm exec oxfmt --check --threads=1 on the touched .ts files: clean.
- Standalone tsx reproducer importing the schema body and compiling it
  with the same Ajv configuration as src/gateway/protocol/index.ts:
  19/19 cases pass (covering the 8 PR test scenarios above plus their
  primitive variants).
- pnpm test src/gateway/protocol/agent-params-validator.test.ts is
  expected to pass on CI; local run was blocked by registry access
  while preparing the github-pinned @openclaw/fs-safe workspace dep.

Changelog

Added one bullet under ## Unreleased -> ### Changes describing the
namespace + alias and citing openclaw#74635 and openclaw#62102.

Fixes openclaw#74635.
Fixes openclaw#62102.
Refs openclaw#69139, openclaw#72565, openclaw#75901.
jeffrey701 added a commit to jeffrey701/openclaw that referenced this pull request May 12, 2026
… alias on AgentParamsSchema

Paperclip and other external agents inject a root-level metadata blob
when invoking agents via the openclaw_gateway adapter, but
AgentParamsSchema is declared with additionalProperties: false so the
gateway rejects the entire payload before dispatch:

    invalid agent params: at root: unexpected property 'paperclip'

Reported by openclaw#74635 (Paperclip rev 3494e84 vs OpenClaw 2026.4.26
be8c246) and openclaw#62102. Three earlier PRs proposed a vendor-named root
field (openclaw#69139, openclaw#72565, openclaw#75901) - all closed without merge - so this
lands the fix as a generic namespace plus a backward-compatibility
alias instead.

Schema (src/gateway/protocol/schema/agent.ts)

- AgentParamsSchema gains 'adapterMeta: Type.Optional(Type.Record(
  Type.String(), Type.Unknown()))'. Each external agent or plugin
  adapter writes under its own top-level key here
  (adapterMeta: { paperclip: {...}, greptile: {...} }); the gateway
  accepts the bag as-is and never inspects it. New adapters can land
  protocol-side without growing the schema.
- AgentParamsSchema also gains 'paperclip: Type.Optional(Type.Unknown())'
  as a backward-compatibility alias, with a comment marking it for
  removal once the published Paperclip adapter cuts a release that
  nests under adapterMeta.paperclip. Heartbeats from current Paperclip
  releases keep dispatching during the transition.
- additionalProperties: false on AgentParamsSchema is intentionally
  untouched. Truly unknown root fields (e.g. typo'd 'idempotnecyKey')
  still fail validation before dispatch.

Swift bindings (apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift)

Mirror the two new fields on the AgentParams struct in all four
codegen positions (declaration, init signature, init body, CodingKeys),
following the existing 'inputprovenance' and 'cleanupbundlemcponrunend'
pattern:

    public let adaptermeta: [String: AnyCodable]?
    public let paperclip: AnyCodable?

The macOS-side mirror was deleted upstream so only the shared one needs
to be regenerated.

Tests (src/gateway/protocol/agent-params-validator.test.ts, new)

- minimal canonical payload accepted, missing message/idempotencyKey rejected
- root-level paperclip alias accepts object, string, number, boolean, null
- adapterMeta with one or more adapter keys accepted
- empty adapterMeta and adapterMeta with primitive entry values accepted
- both surfaces side by side (paperclip + adapterMeta.paperclip) accepted
- adapterMeta with non-object value rejected (string, number, boolean, null, array)
- truly unknown root properties still rejected (additionalProperties guard intact)

Verification

- pnpm exec oxfmt --check --threads=1 on the touched .ts files: clean.
- Standalone tsx reproducer importing the schema body and compiling it
  with the same Ajv configuration as src/gateway/protocol/index.ts:
  19/19 cases pass (covering the 8 PR test scenarios above plus their
  primitive variants).
- pnpm test src/gateway/protocol/agent-params-validator.test.ts is
  expected to pass on CI; local run was blocked by registry access
  while preparing the github-pinned @openclaw/fs-safe workspace dep.

Changelog

Added one bullet under ## Unreleased -> ### Changes describing the
namespace + alias and citing openclaw#74635 and openclaw#62102.

Fixes openclaw#74635.
Fixes openclaw#62102.
Refs openclaw#69139, openclaw#72565, openclaw#75901.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui gateway Gateway runtime size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant