Skip to content

feat(gateway): add SDK task ledger RPCs#74847

Merged
BunsDev merged 16 commits intoopenclaw:mainfrom
tmimmanuel:fix/74707-task-ledger-rpcs
May 9, 2026
Merged

feat(gateway): add SDK task ledger RPCs#74847
BunsDev merged 16 commits intoopenclaw:mainfrom
tmimmanuel:fix/74707-task-ledger-rpcs

Conversation

@tmimmanuel
Copy link
Copy Markdown
Contributor

@tmimmanuel tmimmanuel commented Apr 30, 2026

Summary

  • Problem: @openclaw/sdk exposed oc.tasks.*, but list, get, and cancel still threw unsupported errors because Gateway had no SDK-facing task ledger RPCs.
  • Why it matters: OpenMeow and other app clients need stable task visibility for detached/background work without reading internal logs or CLI-only surfaces.
  • What changed: Added tasks.list, tasks.get, and tasks.cancel Gateway RPCs, SDK methods/types, protocol schemas, scopes, docs, and regression coverage.
  • What did NOT change (scope boundary): This does not add tool invocation, artifact APIs, environment provisioning, or new task runtime semantics.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause (if applicable)

  • Root cause: Gateway already had a durable task registry, but no public RPC contract or SDK bridge exposed it to external app clients.
  • Missing detection / guardrail: SDK coverage only locked in unsupported task errors instead of the app-client task ledger contract.
  • Contributing context (if known): The OpenMeow gap map calls out tasks.list, tasks.get, and tasks.cancel as missing basics.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this: Unit test and seam / integration test.
  • Target test or file: src/gateway/server-methods/tasks.test.ts, src/gateway/protocol/index.test.ts, packages/sdk/src/index.test.ts, packages/sdk/src/index.e2e.test.ts.
  • Scenario the test should lock in: SDK task methods route to Gateway RPCs, task statuses are app-facing and stable, filters work, scopes are classified, and cancel returns a clear result contract.
  • Why this is the smallest reliable guardrail: It exercises the protocol and SDK seams without requiring a live detached task runtime.
  • Existing test that already covers this (if any): Existing task registry tests cover the underlying task lifecycle.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

oc.tasks.list(), oc.tasks.get(taskId), and oc.tasks.cancel(taskId) now call Gateway task ledger RPCs instead of throwing unsupported errors.

Diagram (if applicable)

Before:
[external app] -> [@openclaw/sdk oc.tasks.*] -> [unsupported error]

After:
[external app] -> [@openclaw/sdk oc.tasks.*] -> [Gateway tasks.* RPC] -> [durable task registry]

Security Impact (required)

  • New permissions/capabilities? (Yes/No) Yes
  • Secrets/tokens handling changed? (Yes/No) No
  • New/changed network calls? (Yes/No) No
  • Command/tool execution surface changed? (Yes/No) No
  • Data access scope changed? (Yes/No) Yes
  • If any Yes, explain risk + mitigation: tasks.list and tasks.get require operator.read; tasks.cancel requires operator.write. The RPCs expose task metadata from the existing durable task registry and do not expose secrets.

Repro + Verification

Environment

  • OS: Ubuntu/Linux local workspace
  • Runtime/container: Node 22.22.0 via nvm, pnpm 10.33.2
  • Model/provider: N/A
  • Integration/channel (if any): Gateway WebSocket RPC / @openclaw/sdk
  • Relevant config (redacted): N/A

Steps

  1. On current main, call oc.tasks.list(), oc.tasks.get("task-id"), or oc.tasks.cancel("task-id").
  2. Observe the SDK unsupported error.
  3. Apply this PR.
  4. Call the same SDK methods against a Gateway with task records.

Expected

  • SDK task methods route to Gateway task ledger RPCs and return stable task summaries or cancel results.

Actual

  • Before this PR, SDK task methods throw unsupported errors.

Real behavior proof

  • Behavior or issue addressed: Issue Gateway RPC: add SDK-facing task ledger APIs #74707 - @openclaw/sdk exposed oc.tasks.list, oc.tasks.get, and oc.tasks.cancel, but those methods threw unsupported errors because Gateway had no SDK-facing task ledger RPCs. This PR wires the three RPCs end-to-end (Gateway handlers, protocol schemas, scopes, SDK methods) so app clients like OpenMeow can read and cancel detached/background work over WebSocket.

  • Real environment tested: Ubuntu 24.04 workstation, Node 22.22.0 via nvm, repo at PR head bddac58c51, OPENCLAW_STATE_DIR pointed at a fresh tmp directory so the real durable task registry is exercised. Live invocation of the deployed Gateway RPC handlers via node (through tsx for TypeScript path resolution).

  • Exact steps or command run after this patch:

    1. Checked out the PR branch and confirmed the head SHA via git rev-parse HEAD and gh api /repos/openclaw/openclaw/pulls/74847 --jq .head.sha.
    2. Wrote a standalone node script that imports the new handler module (src/gateway/server-methods/tasks.ts) and the durable task registry (src/tasks/runtime-internal.ts) directly, seeds two real task records (one running subagent task, one completed CLI task), then invokes the three new tasks.* Gateway handlers and prints each RPC response.
    3. Ran the script with node (via tsx for ESM TypeScript): node_modules/.bin/tsx /tmp/proof-tasks.mts. The transcript below is the actual stdout.
  • Evidence after fix:

    Live console output captured from running node/tsx against the new handlers at PR head bddac58c51 (real RPC responses from the deployed handler code, not stubbed):

    == tasks.list (status=running, agentId=main) ==
    [
      true,
      {
        "tasks": [
          {
            "id": "74698734-259a-4537-8c2e-0e4b3c1bf808",
            "taskId": "74698734-259a-4537-8c2e-0e4b3c1bf808",
            "kind": "investigation",
            "runtime": "subagent",
            "status": "running",
            "title": "Investigate flaky upload",
            "agentId": "main",
            "sessionKey": "agent:main:main",
            "childSessionKey": "agent:worker:subagent:child",
            "ownerKey": "agent:main:main",
            "runId": "run-running",
            "createdAt": 1777980688190,
            "updatedAt": 1777980688190
          }
        ]
      }
    ]
    
    == tasks.get (taskId=9483b26e-ef4f-4376-b87d-3b959b9841f4) ==
    [
      true,
      {
        "task": {
          "id": "9483b26e-ef4f-4376-b87d-3b959b9841f4",
          "taskId": "9483b26e-ef4f-4376-b87d-3b959b9841f4",
          "kind": "cli",
          "runtime": "cli",
          "status": "completed",
          "title": "Compile artifact",
          "agentId": "main",
          "sessionKey": "agent:main:main",
          "ownerKey": "agent:main:main",
          "runId": "run-completed",
          "createdAt": 1777980688247,
          "updatedAt": 1777980688247
        }
      }
    ]
    
    == tasks.cancel (taskId=74698734-259a-4537-8c2e-0e4b3c1bf808) ==
    [
      true,
      {
        "found": true,
        "cancelled": false,
        "reason": "Subagent task not found.",
        "task": {
          "id": "74698734-259a-4537-8c2e-0e4b3c1bf808",
          "taskId": "74698734-259a-4537-8c2e-0e4b3c1bf808",
          "kind": "investigation",
          "runtime": "subagent",
          "status": "running",
          "title": "Investigate flaky upload",
          "agentId": "main",
          "sessionKey": "agent:main:main",
          "childSessionKey": "agent:worker:subagent:child",
          "ownerKey": "agent:main:main",
          "runId": "run-running",
          "createdAt": 1777980688190,
          "updatedAt": 1777980688190
        }
      }
    ]
    
  • Observed result after fix:

    • tasks.list with status=running, agentId=main filter returned exactly the seeded subagent task and excluded the completed CLI task. The response payload is the SDK-facing shape promised in the protocol schema (id, taskId, kind, runtime, status, title, agentId, sessionKey, childSessionKey, ownerKey, runId, createdAt, updatedAt).
    • tasks.get against the seeded succeeded registry record returned the contract status completed, confirming the public-status mapping (internal succeeded -> SDK completed) is wired through the handler.
    • tasks.cancel returned the documented { found, cancelled, reason?, task } envelope. Here found=true, cancelled=false, reason="Subagent task not found." because no live subagent runtime was attached to the seeded record - that is the correct contract response for a registry record without a live runtime, and proves the cancel handler reaches the runtime resolver and reports a clear contract-shaped failure instead of throwing.
    • All three handlers respected the durable task registry created via OPENCLAW_STATE_DIR, confirming the Gateway-side surface routes through the existing task ledger.
  • What was not tested: Cancel against a live attached subagent runtime that actually performs an abort (requires a full Gateway with running detached agent). The macOS app OpenClawProtocol Swift model bindings (compiled by Xcode in the macOS app build, not exercised here). Auth-scope rejection over a live WebSocket connection (covered by src/gateway/method-scopes.test.ts and the SDK-side e2e in packages/sdk/src/index.e2e.test.ts). Localized docs (publish repo regenerates separately).

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Lint evidence:

  • git diff --check HEAD~1 HEAD
  • targeted oxlint on changed TS files
  • markdownlint-cli2 docs/concepts/openclaw-sdk.md

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes/No) Yes
  • Config/env changes? (Yes/No) No
  • Migration needed? (Yes/No) No
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: SDK-facing task statuses intentionally differ from internal registry statuses.
  • Mitigation: Tests lock in the public mapping, including succeeded to completed and lost to failed.

@openclaw-barnacle openclaw-barnacle Bot added docs Improvements or additions to documentation app: web-ui App: web-ui gateway Gateway runtime size: L labels Apr 30, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented Apr 30, 2026

Codex review: needs changes before merge.

Summary
Adds Gateway tasks.list, tasks.get, and tasks.cancel RPCs with SDK methods/types, protocol schemas/scopes, generated Swift models, docs, changelog, and regression tests.

Reproducibility: yes. Current main source shows oc.tasks.list/get/cancel still throw unsupported errors and Gateway discovery omits tasks.*; this is source-reproducible without mutating the checkout.

Real behavior proof
Sufficient (terminal): The PR body includes terminal output from a real node/tsx invocation of the new handlers against the durable task registry, showing after-fix tasks.* responses.

Next step before merge
A narrow repair can switch SDK task reads to existing operator-inspection reconciliation and add regression coverage without a new product or security decision.

Security
Cleared: No concrete security or supply-chain regression found; the new task metadata read/cancel surface is gated by existing operator scopes and does not touch dependencies, workflows, or secrets.

Review findings

  • [P2] Use the reconciled task view for SDK reads — src/gateway/server-methods/tasks.ts:157
Review details

Best possible solution:

Land the additive RPC/SDK surface after tasks.list and tasks.get use the reconciled operator-inspection task view and regression coverage locks in stale/lost projection.

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

Yes. Current main source shows oc.tasks.list/get/cancel still throw unsupported errors and Gateway discovery omits tasks.*; this is source-reproducible without mutating the checkout.

Is this the best way to solve the issue?

Yes in direction, but not as-is. Additive RPCs over the existing task registry with operator scopes are the narrow maintainable path, but the read handlers need to reuse existing operator reconciliation before exposing statuses.

Full review comments:

  • [P2] Use the reconciled task view for SDK reads — src/gateway/server-methods/tasks.ts:157
    The existing operator task surface calls reconcileInspectableTasks() / reconcileTaskLookupToken() before displaying records, which projects stale records with missing backing state to lost. This handler filters raw listTaskRecords() results, so tasks.list({ status: "running" }) can keep returning a task that openclaw tasks list/show already reports as lost. Route list/get through the existing operator-inspection reconciliation before mapping summaries.
    Confidence: 0.84

Overall correctness: patch is incorrect
Overall confidence: 0.84

Acceptance criteria:

  • pnpm test src/gateway/server-methods/tasks.test.ts src/gateway/protocol/index.test.ts src/gateway/method-scopes.test.ts packages/sdk/src/index.test.ts packages/sdk/src/index.e2e.test.ts
  • pnpm protocol:check
  • pnpm exec oxfmt --check --threads=1 src/gateway/server-methods/tasks.ts src/gateway/server-methods/tasks.test.ts

What I checked:

  • Current main SDK gap: At current main, TasksNamespace.list, get, and cancel still call unsupportedGatewayApi, so the reported SDK behavior is still present on main. (packages/sdk/src/client.ts:728, 094d0b88a57f)
  • Current main discovery gap: Gateway method discovery on current main lists adjacent tool/environment methods but not tasks.list, tasks.get, or tasks.cancel. (src/gateway/server-methods-list.ts:75, 094d0b88a57f)
  • PR implementation: PR head adds task RPC handlers, but tasks.list filters raw listTaskRecords() output before mapping SDK summaries. (src/gateway/server-methods/tasks.ts:157, 42d73001ae80)
  • Existing operator semantics: The existing CLI task list uses reconcileInspectableTasks() so operator-facing reads project recovered/lost task state before display. (src/commands/tasks.ts:286, 094d0b88a57f)
  • Proof and checks: The PR body supplies terminal output from invoking the new handlers against the durable task registry, and exact-head GitHub check runs for docs/protocol/build/test/security lanes are green. (42d73001ae80)

Likely related people:

  • steipete: Current-main blame in this checkout points the SDK task namespace, task registry cancellation/listing, and operator reconciliation surfaces to Peter Steinberger's recent commit; prior ClawSweeper context also identified this handle around SDK/task-registry maintenance. (role: introduced behavior and adjacent maintainer; confidence: medium; commits: 748fe6b2125a; files: packages/sdk/src/client.ts, src/tasks/task-registry.ts, src/tasks/task-registry.maintenance.ts)
  • BunsDev: BunsDev authored the linked maintainer SDK task-ledger issue and later requested follow-up changes on this PR, making them a strong routing candidate for product/API acceptance. (role: feature sponsor and likely follow-up owner; confidence: medium; commits: 42d73001ae80; files: docs/gateway/protocol.md, docs/reference/openclaw-sdk-api-design.md, CHANGELOG.md)

Remaining risk / open question:

  • SDK task reads currently use raw task records rather than existing operator reconciliation, so stale records can be exposed with a misleading active status.

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

@tmimmanuel tmimmanuel force-pushed the fix/74707-task-ledger-rpcs branch from 06a19cb to 1368f9d Compare May 1, 2026 11:51
@openclaw-barnacle openclaw-barnacle Bot added triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 5, 2026
@BunsDev BunsDev self-assigned this May 5, 2026
BunsDev and others added 3 commits May 5, 2026 08:43
…er-rpcs

# Conflicts:
#	docs/concepts/openclaw-sdk.md
#	packages/sdk/src/index.test.ts
#	src/gateway/server-methods-list.ts
@openclaw-barnacle openclaw-barnacle Bot added the proof: supplied External PR includes structured after-fix real behavior proof. label May 5, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 6, 2026
…er-rpcs

# Conflicts:
#	apps/macos/Sources/OpenClawProtocol/GatewayModels.swift
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a public, SDK-facing “task ledger” surface to the Gateway so external app clients can list, fetch, and cancel durable background task records over the existing RPC transport (closing the current oc.tasks.* unsupported gap).

Changes:

  • Added Gateway RPC handlers for tasks.list, tasks.get, and tasks.cancel, including status mapping and pagination cursor support.
  • Introduced protocol schemas/types + scope classification (operator.read for list/get; operator.write for cancel) with corresponding Gateway/SKD tests.
  • Implemented @openclaw/sdk task types and methods, and updated docs + Swift protocol models.

Reviewed changes

Copilot reviewed 21 out of 21 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/tasks/task-registry.ts Adds optional cancel reason propagation into task cancellation and stored task error text.
src/tasks/detached-task-runtime-contract.ts Extends detached task cancel contract to accept an optional reason.
src/gateway/server-methods/tasks.ts Implements the new Gateway RPC handlers and TaskRecord → TaskSummary mapping.
src/gateway/server-methods/tasks.test.ts Adds handler-level coverage for list/get/cancel behavior and status mapping.
src/gateway/server-methods.ts Registers the new tasks handlers in the core Gateway handler map.
src/gateway/server-methods-list.ts Advertises the new tasks.* methods in the base method list.
src/gateway/protocol/schema/types.ts Exposes schema-derived TS types for the new tasks RPCs.
src/gateway/protocol/schema/tasks.ts Defines TypeBox schemas for task summaries, params, and results.
src/gateway/protocol/schema/protocol-schemas.ts Adds tasks schemas to the ProtocolSchemas registry.
src/gateway/protocol/schema.ts Re-exports the tasks schema module.
src/gateway/protocol/index.ts Wires tasks schemas/types + AJV validators into the protocol index exports.
src/gateway/protocol/index.test.ts Adds validation tests ensuring SDK-facing statuses/fields are accepted and internal ones rejected.
src/gateway/method-scopes.ts Adds tasks.list/get to read scope group and tasks.cancel to write scope group.
src/gateway/method-scopes.test.ts Verifies method → scope resolution for new tasks methods.
packages/sdk/src/types.ts Adds SDK task ledger types (TaskSummary, status union, params/results).
packages/sdk/src/index.ts Re-exports the new SDK task types.
packages/sdk/src/index.test.ts Updates SDK unit tests to assert tasks methods call the Gateway methods (instead of throwing unsupported).
packages/sdk/src/index.e2e.test.ts Extends websocket e2e fake gateway to implement tasks.* and asserts SDK integration.
packages/sdk/src/client.ts Implements oc.tasks.list/get/cancel against the RPC namespace with typed return values.
docs/concepts/openclaw-sdk.md Updates docs to mark oc.tasks as Ready, lists exported task types, and adds usage examples.
apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift Adds Swift model bindings for the new tasks RPC shapes.

Comment thread src/gateway/server-methods/tasks.ts
Comment thread apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift Outdated
Comment thread docs/concepts/openclaw-sdk.md Outdated
@BunsDev
Copy link
Copy Markdown
Member

BunsDev commented May 9, 2026

@copilot apply changes based on the comments in this thread

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 9, 2026
@openclaw-barnacle openclaw-barnacle Bot added the scripts Repository scripts label May 9, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 9, 2026
@BunsDev
Copy link
Copy Markdown
Member

BunsDev commented May 9, 2026

Thanks @tmimmanuel — this is a useful addition. The task-ledger RPCs give SDK clients a clean way to list, inspect, and cancel durable background tasks through the Gateway.

I tightened the public surface before merge with sanitized task status text, stronger Swift typing for TasksCancelResult.task, protocol/docs updates, and verification coverage. Appreciate the contribution!

@BunsDev BunsDev merged commit 2945948 into openclaw:main May 9, 2026
115 of 116 checks passed
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 docs Improvements or additions to documentation gateway Gateway runtime proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. scripts Repository scripts size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Gateway RPC: add SDK-facing task ledger APIs

4 participants