openclaw - ✅(Solved) Fix SDK: stabilize app-client happy path for agents, sessions, runs [10 pull requests, 6 comments, 4 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#74704Fetched 2026-04-30 06:21:02
View on GitHub
Comments
6
Participants
4
Timeline
25
Reactions
3
Author
Timeline (top)
cross-referenced ×11commented ×6assigned ×2mentioned ×2

Root Cause

OpenMeow is a useful dogfood client because it exercises the core app-SDK flow without requiring future managed/cloud features.

PR fix notes

PR #74750: fix(sdk): stabilize run event chat projections

Description (problem / solution / changelog)

Summary

  • Problem: Run.events() could expose raw Gateway chat projection frames for SDK runs, leaking duplicate app-facing events into the normalized per-run stream.
  • Why it matters: External app clients expect Run.events() to provide stable SDK event types for UI state, with raw Gateway frames reserved for rawEvents().
  • What changed: Per-run streams now suppress duplicate chat projection frames when canonical SDK events are already present, and normalize chat-only projection frames into stable SDK events.
  • What did NOT change (scope boundary): This does not fix the separate cancel response / stream terminal / wait result disagreement also captured in #74704.

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

  • Related #74704
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: Gateway chat projection frames normalize to SDK raw events while retaining runId, so Run.events() treated them as part of the stable per-run SDK stream.
  • Missing detection / guardrail: SDK tests covered replayed agent events, but not duplicate chat projection frames or chat-only run streams.
  • Contributing context (if known): Owner dogfood evidence on #74704 identified raw chat events leaking into run.events().

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: packages/sdk/src/index.test.ts
  • Scenario the test should lock in: a per-run SDK stream with canonical agent events suppresses duplicate raw chat delta / final projections.
  • Why this is the smallest reliable guardrail: the existing fake transport exercises SDK normalization, replay, and per-run filtering without requiring a live Gateway.
  • Existing test that already covers this (if any): none.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

Run.events() no longer surfaces duplicate raw chat projection frames when stable SDK events are already available. For chat-only streams, the SDK now maps chat delta to assistant.delta and chat final to run.completed. Raw Gateway access remains available through oc.rawEvents().

Diagram (if applicable)

N/A

Before:
Gateway agent/chat frames -> Run.events() -> stable SDK events plus duplicate raw chat frames

After:
Gateway agent/chat frames -> Run.events() -> stable SDK events only

Chat-only fallback:
Gateway chat delta/final -> Run.events() -> assistant.delta/run.completed

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: local Linux checkout
  • Runtime/container: Node v24.11.0 from /tmp/node-v24.11.0-linux-x64
  • Model/provider: N/A
  • Integration/channel (if any): SDK event stream
  • Relevant config (redacted): N/A

Steps

  1. Start a run through the SDK fake transport.
  2. Emit canonical agent lifecycle / assistant events and duplicate Gateway chat projection frames for the same run id.
  3. Iterate run.events().
  4. Repeat with a chat-only stream where no canonical lifecycle events exist.

Expected

  • Duplicate chat projection frames do not appear as raw events in Run.events().
  • Chat-only delta / final projections still produce stable SDK assistant.delta / run.completed events.
  • oc.rawEvents() remains the raw Gateway escape hatch.

Actual

Before this fix, raw chat projection frames leaked into Run.events().

Evidence

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

Commands run:

PATH=/tmp/node-v24.11.0-linux-x64/bin:$PATH corepack pnpm test packages/sdk/src/index.test.ts
corepack pnpm exec oxfmt --check --threads=1 packages/sdk/src/client.ts packages/sdk/src/index.test.ts
git diff --check
PATH=/tmp/node-v24.11.0-linux-x64/bin:$PATH corepack pnpm check:changelog-attributions
PATH=/tmp/node-v24.11.0-linux-x64/bin:$PATH corepack pnpm changed:lanes --json

Results:

  • Targeted SDK unit test: pass
  • Targeted formatting check: pass
  • Whitespace diff check: pass
  • Changelog attribution check: pass
  • Changed lanes: core, coreTests

Additional check:

PATH=/tmp/node-v24.11.0-linux-x64/bin:$PATH corepack pnpm test packages/sdk/src/index.e2e.test.ts

Result: failed by wrapper no-output timeout after retry, exit 143, with no assertion details.

Human Verification (required)

  • Verified scenarios:
    • Duplicate chat delta / final projection frames are suppressed when canonical SDK agent events exist.
    • Chat-only delta / final projection frames normalize to stable SDK event types.
    • Raw Gateway access remains unchanged through rawEvents().
  • Edge cases checked:
    • Fast-run replay path.
    • Per-run live stream path.
    • Chat text extraction from array text content.
  • What you did not verify:
    • Full repo pnpm check / pnpm test.
    • SDK e2e completion, because the local wrapper timed out with no output.
  • AI assistance:
    • AI-assisted implementation and review. Targeted SDK unit coverage passed under Node 24.11.0.

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.

No PR review conversations exist yet.

Compatibility / Migration

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

Risks and Mitigations

  • Risk: A caller intentionally consumed raw chat projection frames from Run.events().
    • Mitigation: oc.rawEvents() remains available for raw Gateway frames; Run.events() keeps the stable per-run SDK contract.
  • Risk: This PR does not close all of #74704.
    • Mitigation: PR uses Related #74704; the cancel response / stream terminal / wait result disagreement remains separate follow-up work.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • packages/sdk/src/client.ts (modified, +107/-8)
  • packages/sdk/src/index.test.ts (modified, +209/-1)

PR #74751: fix(gateway): align sessions abort wait semantics

Description (problem / solution / changelog)

Summary

  • emit normalized lifecycle cancellation events when chat/session runs are aborted
  • preserve cancelled wait snapshots so agent.wait does not report completed/ok after sessions.abort
  • use the correct wait-dedupe namespace for chat-send vs agent-kind runs, avoiding agent RPC cache collision

Relationship to #74750

  • #74750 owns the SDK Run.events() chat-projection behavior.
  • This PR is now trimmed to the Gateway cancel/wait semantics only, so the two PRs no longer compete.

Verification

  • git diff --check origin/main...HEAD
  • node scripts/test-projects.mjs src/gateway/server.chat.gateway-server-chat.test.ts src/gateway/server-methods/agent.test.ts

Refs #74704.

Changed files

  • src/gateway/chat-abort.ts (modified, +14/-0)
  • src/gateway/server-methods/agent.test.ts (modified, +2/-0)
  • src/gateway/server-methods/chat.ts (modified, +11/-9)
  • src/gateway/server-methods/sessions.ts (modified, +35/-1)
  • src/gateway/server.chat.gateway-server-chat-b.test.ts (modified, +5/-1)
  • src/gateway/server.chat.gateway-server-chat.test.ts (modified, +37/-0)

PR #74769: feat(gateway): add artifact RPCs

Description (problem / solution / changelog)

Summary

Describe the problem and fix in 2–5 bullets:

  • Problem: Gateway clients have no supported artifact RPC surface, so SDK/app clients must scrape chat history and infer downloadable media themselves.
  • Why it matters: External app clients need stable artifact discovery and download semantics for generated or attached media without depending on transcript internals.
  • What changed: Added artifacts.list, artifacts.get, and artifacts.download gateway RPCs over session transcript artifact blocks, with protocol schemas, method discovery, read-scope authorization, and typed unsupported/not-found errors.
  • What did NOT change (scope boundary): This does not add a new artifact store or expose arbitrary local file paths; unsupported artifact sources return explicit unsupported errors.

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

  • Closes #74706
  • Related #74704
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: Artifacts existed only as transcript content blocks, with no supported gateway RPC projection for SDK/app clients.
  • Missing detection / guardrail: There was no focused gateway test asserting artifact list/get/download behavior or typed missing/unsupported errors.
  • Contributing context (if known): The SDK happy path needs artifact access without requiring clients to parse chat history payload details.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/gateway/server-methods/artifacts.test.ts
  • Scenario the test should lock in: Session transcript media blocks are listed as stable artifact summaries, can be fetched by ID, can be downloaded as base64 bytes, and missing/unsupported query paths return typed errors.
  • Why this is the smallest reliable guardrail: The new behavior is a gateway RPC projection over existing transcript state, so handler-level tests cover the API contract directly.
  • Existing test that already covers this (if any): N/A
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

SDK and app clients can call artifacts.list, artifacts.get, and artifacts.download with sessionKey, runId, or taskId query context. Inline transcript artifacts download as base64 bytes; URL-backed artifacts return a URL; unsupported sources return a typed error.

Diagram (if applicable)

Before:
SDK client -> chat.history -> parse transcript media internals

After:
SDK client -> artifacts.list/get/download -> normalized artifact contract

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (Yes)
  • If any Yes, explain risk + mitigation: Artifact RPCs expose only artifacts already present in authorized chat/session transcript data and are gated by existing operator.read scope. They do not read arbitrary local file paths.

Repro + Verification

Environment

  • OS: Linux
  • Runtime/container: Node 22.14.0, pnpm
  • Model/provider: N/A
  • Integration/channel (if any): Gateway RPC
  • Relevant config (redacted): Default test config

Steps

  1. Seed a session transcript message with an image/file content block.
  2. Call artifacts.list with the session key.
  3. Call artifacts.get and artifacts.download with the returned artifact ID.
  4. Call with missing/unknown artifact context.

Expected

  • Artifact summaries are stable and omit raw bytes.
  • artifacts.download returns base64 bytes or URL depending on source.
  • Missing/unsupported cases return typed errors.

Actual

  • Matches expected after this PR.

Evidence

Attach at least one:

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

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: artifacts.list, artifacts.get, artifacts.download, runId-to-session lookup, missing query scope, missing artifact ID, protocol schema compilation, method-scope discovery.
  • Edge cases checked: Inline base64 artifact bytes are omitted from summaries and returned only from download.
  • What you did not verify: A live SDK/OpenMeow client against a running gateway.

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.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

Compatibility / Migration

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

Risks and Mitigations

  • Risk: The first artifact source is intentionally conservative and may return artifact_download_unsupported for transcript blocks that reference local-only paths.
    • Mitigation: This avoids exposing arbitrary local filesystem paths while establishing the stable RPC contract for inline and URL-backed artifacts.

Changed files

  • src/gateway/method-scopes.ts (modified, +3/-0)
  • src/gateway/protocol/index.ts (modified, +24/-0)
  • src/gateway/protocol/schema.ts (modified, +1/-0)
  • src/gateway/protocol/schema/artifacts.ts (added, +73/-0)
  • src/gateway/protocol/schema/protocol-schemas.ts (modified, +16/-0)
  • src/gateway/protocol/schema/types.ts (modified, +7/-0)
  • src/gateway/server-methods-list.ts (modified, +3/-0)
  • src/gateway/server-methods.ts (modified, +2/-0)
  • src/gateway/server-methods/artifacts.test.ts (added, +180/-0)
  • src/gateway/server-methods/artifacts.ts (added, +375/-0)

PR #74779: fix(sdk): stabilize run event chat projections

Description (problem / solution / changelog)

Summary

  • Problem: Run.events() could expose raw Gateway chat projection frames for SDK runs, leaking duplicate app-facing events into the normalized per-run stream.
  • Why it matters: External app clients expect Run.events() to provide stable SDK event types for UI state, with raw Gateway frames reserved for rawEvents().
  • What changed: Per-run streams now suppress duplicate chat projection frames when canonical SDK events are already present, and normalize chat-only projection frames into stable SDK events.
  • What did NOT change (scope boundary): This does not fix the separate cancel response / stream terminal / wait result disagreement also captured in SDK: stabilize app-client happy path for agents, sessions, runs #74704.

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 chat projection frames normalize to SDK raw events while retaining runId, so Run.events() treated them as part of the stable per-run SDK stream.
  • Missing detection / guardrail: SDK tests covered replayed agent events, but not duplicate chat projection frames or chat-only run streams.
  • Contributing context (if known): Owner dogfood evidence on SDK: stabilize app-client happy path for agents, sessions, runs #74704 identified raw chat events leaking into run.events().

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:

    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: packages/sdk/src/index.test.ts

  • Scenario the test should lock in: a per-run SDK stream with canonical agent events suppresses duplicate raw chat delta / final projections.

  • Why this is the smallest reliable guardrail: the existing fake transport exercises SDK normalization, replay, and per-run filtering without requiring a live Gateway.

  • Existing test that already covers this (if any): none.

  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

Run.events() no longer surfaces duplicate raw chat projection frames when stable SDK events are already available. For chat-only streams, the SDK now maps chat delta to assistant.delta and chat final to run.completed. Raw Gateway access remains available through oc.rawEvents().

Diagram (if applicable)

N/A

Before:
Gateway agent/chat frames -> Run.events() -> stable SDK events plus duplicate raw chat frames

After:
Gateway agent/chat frames -> Run.events() -> stable SDK events only

Chat-only fallback:
Gateway chat delta/final -> Run.events() -> assistant.delta/run.completed

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: local Linux checkout
  • Runtime/container: Node v24.11.0 from /tmp/node-v24.11.0-linux-x64
  • Model/provider: N/A
  • Integration/channel (if any): SDK event stream
  • Relevant config (redacted): N/A

Steps

  1. Start a run through the SDK fake transport.
  2. Emit canonical agent lifecycle / assistant events and duplicate Gateway chat projection frames for the same run id.
  3. Iterate run.events().
  4. Repeat with a chat-only stream where no canonical lifecycle events exist.

Expected

  • Duplicate chat projection frames do not appear as raw events in Run.events().
  • Chat-only delta / final projections still produce stable SDK assistant.delta / run.completed events.
  • oc.rawEvents() remains the raw Gateway escape hatch.

Actual

Before this fix, raw chat projection frames leaked into Run.events().

Evidence

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

Commands run:

PATH=/tmp/node-v24.11.0-linux-x64/bin:$PATH corepack pnpm test packages/sdk/src/index.test.ts
corepack pnpm exec oxfmt --check --threads=1 packages/sdk/src/client.ts packages/sdk/src/index.test.ts
git diff --check
PATH=/tmp/node-v24.11.0-linux-x64/bin:$PATH corepack pnpm check:changelog-attributions
PATH=/tmp/node-v24.11.0-linux-x64/bin:$PATH corepack pnpm changed:lanes --json

Results:

  • Targeted SDK unit test: pass
  • Targeted formatting check: pass
  • Whitespace diff check: pass
  • Changelog attribution check: pass
  • Changed lanes: core, coreTests

Additional check:

PATH=/tmp/node-v24.11.0-linux-x64/bin:$PATH corepack pnpm test packages/sdk/src/index.e2e.test.ts

Result: failed by wrapper no-output timeout after retry, exit 143, with no assertion details.

Human Verification (required)

  • Verified scenarios:

    • Duplicate chat delta / final projection frames are suppressed when canonical SDK agent events exist.
    • Chat-only delta / final projection frames normalize to stable SDK event types.
    • Raw Gateway access remains unchanged through rawEvents().
  • Edge cases checked:

    • Fast-run replay path.
    • Per-run live stream path.
    • Chat text extraction from array text content.
  • What you did not verify:

    • Full repo pnpm check / pnpm test.
    • SDK e2e completion, because the local wrapper timed out with no output.
  • AI assistance:

    • AI-assisted implementation and review. Targeted SDK unit coverage passed under Node 24.11.0.

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.

No PR review conversations exist yet.

Compatibility / Migration

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

Risks and Mitigations

  • Risk: A caller intentionally consumed raw chat projection frames from Run.events().

    • Mitigation: oc.rawEvents() remains available for raw Gateway frames; Run.events() keeps the stable per-run SDK contract.
  • Risk: This PR does not close all of SDK: stabilize app-client happy path for agents, sessions, runs #74704.

    • Mitigation: PR uses Related #74704; the cancel response / stream terminal / wait result disagreement remains separate follow-up work.

Changed files

  • docs/concepts/openclaw-sdk.md (modified, +122/-0)
  • packages/sdk/src/index.test.ts (modified, +209/-0)

PR #74797: fix(sdk): normalize run chat projections

Description (problem / solution / changelog)

Summary

  • Problem: Run.events() can surface raw Gateway chat projection frames for SDK runs, which creates duplicate app-facing events instead of a stable normalized per-run stream.
  • Why it matters: OpenMeow-style app clients need Run.events() for UI state, while raw Gateway frames should remain available through rawEvents().
  • What changed: per-run streams now suppress duplicate raw chat projection frames when canonical SDK run events exist, and normalize chat-only delta / final projections to stable SDK event types.
  • What did NOT change (scope boundary): this does not change Gateway cancel/wait semantics and does not touch the separate #74751 abort/wait work.

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

  • Closes #
  • Related #74704
  • Related #74750
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: Gateway chat projection frames normalize to SDK raw events while retaining the same runId, so Run.events() treated them as part of the stable run event stream.
  • Missing detection / guardrail: SDK tests covered fast replayed agent events, but not duplicate chat projection frames or chat-only projection fallback.
  • Contributing context (if known): live #74704 dogfood evidence identified raw chat events leaking into run.events().

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: packages/sdk/src/index.test.ts
  • Scenario the test should lock in: canonical agent stream events suppress duplicate raw chat projections, and chat-only projection streams still produce assistant.delta and run.completed events.
  • Why this is the smallest reliable guardrail: the fake SDK transport exercises event normalization, replay, and per-run filtering without a live Gateway.
  • Existing test that already covers this (if any): fast run replay coverage existed, but it did not include chat projection frames.
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

Run.events() no longer emits duplicate raw chat projection frames when stable SDK events already exist for the run. Chat-only streams still produce normalized SDK events. Raw Gateway event access remains available through oc.rawEvents().

Diagram (if applicable)

Before:
Gateway agent/chat frames -> Run.events() -> SDK events + duplicate raw chat frames

After:
Gateway agent/chat frames -> Run.events() -> stable SDK events
Gateway chat-only frames -> Run.events() -> assistant.delta/run.completed fallback

Security Impact (required)

  • New permissions/capabilities? (Yes/No) No
  • 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) No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Linux
  • Runtime/container: Node 22 + pnpm
  • Model/provider: N/A
  • Integration/channel (if any): SDK event stream
  • Relevant config (redacted): fake SDK transport

Steps

  1. Start an SDK run where canonical agent frames and duplicate chat projection frames share a run id.
  2. Iterate run.events().
  3. Start an SDK run where only chat projection frames are present.
  4. Iterate run.events().

Expected

  • Duplicate raw chat frames are suppressed when canonical SDK events exist.
  • Chat-only projections normalize to assistant.delta and run.completed.
  • rawEvents() remains the raw Gateway escape hatch.

Actual

  • Matches expected in targeted tests.

Evidence

Attach at least one:

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

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: duplicate chat projection suppression, chat-only projection fallback normalization, fast replay path, formatting, whitespace, changelog attribution, and package test typecheck.
  • Edge cases checked: array text content extraction from chat messages and terminal chat final fallback data.
  • What you did not verify: full repo pnpm check / pnpm test, and live Gateway/OpenMeow adapter execution.

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.

If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.

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: a caller intentionally consumed raw chat projection frames from Run.events().
    • Mitigation: raw Gateway frames remain available through oc.rawEvents(); Run.events() is the normalized app-client stream.
  • Risk: this overlaps with #74750.
    • Mitigation: this is a single-commit, narrow patch for the same #74704 dogfood gap; maintainers can choose the cleaner branch.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • packages/sdk/src/client.ts (modified, +105/-8)
  • packages/sdk/src/index.test.ts (modified, +173/-1)

PR #74781: fix(gateway): snapshot all session-aborted runs

Description (problem / solution / changelog)

Related https://github.com/openclaw/openclaw/issues/74704

Summary

  • Problem: #74751 records the terminal wait snapshot for only the first run returned by a session-wide sessions.abort.
  • Why it matters: app clients that abort a session with multiple active runs can see only one run become terminal while the other aborted runs still wait or report stale state.
  • What changed: normalize every returned run ID and write the RPC stop/timeout dedupe snapshot for each aborted run.
  • What did NOT change: the existing sessions.abort response shape still reports the first abortedRunId for compatibility.

Testing

  • Not run locally, per request.
  • git diff --check HEAD~1..HEAD passed.

Changed files

  • src/gateway/server-methods/sessions.ts (modified, +21/-19)
  • src/gateway/server.chat.gateway-server-chat.test.ts (modified, +55/-0)

PR #74804: feat(gateway): add SDK-facing tools.invoke RPC

Description (problem / solution / changelog)

Summary

  • Problem: @openclaw/sdk exposes a tools namespace, but oc.tools.invoke() had no Gateway RPC method to call and remained unsupported.
  • Why it matters: SDK clients need a typed WebSocket path for generic tool invocation that follows the same Gateway auth, tool policy, deny-list, and plugin approval semantics as the existing HTTP /tools/invoke route.
  • What changed: adds tools.invoke to the Gateway RPC surface, protocol schemas, method discovery, scope gating, SDK client/types, and docs; shared Gateway tool-invoke logic now backs both HTTP and RPC paths.
  • What did NOT change (scope boundary): no new tool policy bypass, no new default tool allow-list expansion, no config migration, and no replay cache beyond using idempotencyKey as the stable tool-call id when supplied.

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

  • Closes #74705
  • Related #74704
  • This PR fixes a bug or regression

Root Cause (if applicable)

N/A

Regression Test Plan (if applicable)

N/A

User-visible / Behavior Changes

SDK clients can now call oc.tools.invoke(name, params) through the Gateway. The RPC method accepts SDK-style name and HTTP-compatible tool aliases, optional action, args, sessionKey, agentId, confirm, reserved dryRun, and idempotencyKey fields.

Diagram (if applicable)

Before:
SDK oc.tools.invoke() -> unsupported error
HTTP POST /tools/invoke -> existing Gateway tool path

After:
SDK oc.tools.invoke() -> WS tools.invoke -> shared Gateway tool path -> policy/deny-list/approval/tool result
HTTP POST /tools/invoke -> shared Gateway tool path -> existing HTTP envelope

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) Yes
  • Data access scope changed? (Yes/No) Yes
  • If any Yes, explain risk + mitigation: This exposes an existing direct tool-invoke capability over Gateway WS for SDK clients. It is gated by operator.write, reuses the existing Gateway tool policy chain and HTTP deny-list semantics, preserves owner-only filtering, and reports plugin approval-needed refusals unless the caller explicitly opts into confirm: true.

Repro + Verification

Environment

  • OS: Ubuntu 24.04
  • Runtime/container: Node 22 / pnpm dev checkout
  • Model/provider: N/A
  • Integration/channel (if any): Gateway RPC + SDK
  • Relevant config (redacted): default local test config

Steps

  1. Call SDK oc.tools.invoke() before this change.
  2. Observe it throws the existing unsupported namespace error because no Gateway tools.invoke method exists.
  3. Apply this PR and call oc.tools.invoke("sessions_list", { args: {}, sessionKey: "main" }).
  4. Verify the SDK sends tools.invoke, the Gateway enforces operator.write, and the response uses a typed tool result/refusal envelope.

Expected

  • SDK clients can invoke allowed tools through Gateway RPC.
  • Disallowed or approval-required tools do not bypass policy and return typed refusal state.
  • HTTP /tools/invoke behavior remains compatible.

Actual

  • Implemented as expected in targeted unit, gateway, agent, SDK, and SDK e2e coverage.

Evidence

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

Human Verification (required)

  • Verified scenarios: SDK tools.invoke dispatch, Gateway tools.invoke handler success envelope, malformed RPC params rejection, operator.write method scope, HTTP /tools/invoke compatibility, and plugin approval-needed typed refusal without opening an approval request by default.
  • Edge cases checked: HTTP tool alias compatibility, SDK name field, high-risk deny-list preservation, owner-only filtering path, configured session fallback, gateway.tools.allow/deny precedence, and confirm: false approval reporting behavior.
  • What you did not verify: live third-party SDK consumer behavior outside the repo tests.

Commands run:

git diff --check refs/remotes/openclaw/main...HEAD
pnpm test src/gateway/tools-invoke-http.test.ts src/gateway/method-scopes.test.ts src/agents/pi-tools.before-tool-call.embedded-mode.test.ts packages/sdk/src/index.test.ts packages/sdk/src/index.e2e.test.ts src/gateway/protocol/index.test.ts -- --reporter=verbose
pnpm check:changed --base refs/remotes/openclaw/main

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: The new RPC surface could drift from the HTTP tool-invoke behavior over time.
    • Mitigation: HTTP and RPC now share the same Gateway tool-invoke helper, and tests cover both surfaces.
  • Risk: Approval behavior could unexpectedly open approval prompts for SDK callers.
    • Mitigation: the default RPC path reports typed approval-needed refusal; callers must pass confirm: true to request approval explicitly.

Changed files

  • apps/macos/Sources/OpenClawProtocol/GatewayModels.swift (modified, +106/-0)
  • apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift (modified, +106/-0)
  • docs/concepts/openclaw-sdk.md (modified, +26/-20)
  • docs/gateway/protocol.md (modified, +9/-1)
  • packages/sdk/src/client.ts (modified, +13/-4)
  • packages/sdk/src/index.e2e.test.ts (modified, +10/-0)
  • packages/sdk/src/index.test.ts (modified, +33/-3)
  • packages/sdk/src/index.ts (modified, +2/-0)
  • packages/sdk/src/types.ts (modified, +20/-0)
  • src/agents/pi-tools.before-tool-call.embedded-mode.test.ts (modified, +28/-0)
  • src/agents/pi-tools.before-tool-call.ts (modified, +25/-0)
  • src/gateway/method-scopes.test.ts (modified, +1/-0)
  • src/gateway/method-scopes.ts (modified, +1/-0)
  • src/gateway/protocol/index.ts (modified, +7/-0)
  • src/gateway/protocol/schema/agents-models-skills.ts (modified, +45/-0)
  • src/gateway/protocol/schema/protocol-schemas.ts (modified, +6/-0)
  • src/gateway/protocol/schema/types.ts (modified, +2/-0)
  • src/gateway/server-methods-list.ts (modified, +1/-0)
  • src/gateway/server-methods.ts (modified, +2/-0)
  • src/gateway/server-methods/tools-invoke.ts (added, +89/-0)
  • src/gateway/tools-invoke-http.test.ts (modified, +88/-0)
  • src/gateway/tools-invoke-http.ts (modified, +18/-222)
  • src/gateway/tools-invoke-shared.ts (added, +291/-0)

PR #74827: fix: chat-only projection fallback sdk event-contract bug

Description (problem / solution / changelog)

Summary

Found one SDK event-contract bug in the new chat-only projection fallback.

What ClawSweeper Is Fixing

  • Medium: Chat-only projection deltas expose full snapshots as appendable deltas (bug)
    • File: packages/sdk/src/client.ts:230
    • Evidence: normalizeChatProjectionEvent() maps the full projected chat text to data.delta for assistant.delta events at packages/sdk/src/client.ts:223. Real chat projection delta payloads carry the full buffered text, not an incremental chunk: Gateway builds message.content[0].text from mergedText at src/gateway/server-chat.ts:410 and src/gateway/server-chat.ts:433, and flushes the full buffered text at src/gateway/server-chat.ts:489. Canonical assistant events keep both full text and incremental delta via buildAssistantStreamData() at src/agents/pi-embedded-subscribe.handlers.messages.ts:356 and src/agents/pi-embedded-subscribe.handlers.messages.ts:606. The SDK docs show consumers appending data.delta directly at docs/concepts/openclaw-sdk.md:103, and the SDK live e2e does the same at packages/sdk/src/index.e2e.test.ts:586. The new test itself normalizes ch...
    • Impact: SDK clients using Run.events() for chat-only streams can duplicate streamed assistant text in UI/output buffers.
    • Suggested fix: track the previous chat projection text per run stream and emit canonical assistant-shaped data, for example { text, delta: text.slice(previous.length) } when the new text extends the previous text, and { text, delta: text, replace: true } or an equivalent replacement signal when it does not.
    • Confidence: high

Expected Repair Surface

  • packages/sdk/src/client.ts
  • packages/sdk/src/index.test.ts

Source And Review Context

Expected validation

  • pnpm check:changed

ClawSweeper already ran:

  • pnpm install because dev dependencies were missing
  • pnpm test packages/sdk/src/index.test.ts passed: 14 tests
  • pnpm exec oxfmt --check --threads=1 packages/sdk/src/client.ts packages/sdk/src/index.test.ts CHANGELOG.md passed
  • pnpm --filter @openclaw/sdk build passed
  • git diff --check 5f13af6b68603c49367e1540212779d1dcafafb2..e6abd9e3d8c451477f1c93c091a205d30aed4d92 passed

Known review limits:

  • Did not run the full repository gate; focused SDK tests/build and PR CI status were enough for this review.
  • No live Gateway run was performed.

ClawSweeper Guardrails

  • Re-check the finding against latest main before changing code.
  • Keep the patch to the narrowest behavior change and matching regression coverage.
  • Do not merge automatically; this PR stays for maintainer review.

ClawSweeper 🐠 replacement reef notes:

  • Cluster: clawsweeper-commit-openclaw-openclaw-e6abd9e3d8c4
  • Source PRs: none
  • Credit: Detected by ClawSweeper commit review for e6abd9e3d8c451477f1c93c091a205d30aed4d92.; Original commit author: bitloi.
  • Validation: pnpm check:changed

fish notes: model gpt-5.5, reasoning medium; reviewed against 94aadfef1056.

Changed files

  • packages/sdk/src/client.ts (modified, +21/-3)
  • packages/sdk/src/index.test.ts (modified, +31/-7)

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

Description (problem / solution / changelog)

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.

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.

Changed files

  • apps/macos/Sources/OpenClawProtocol/GatewayModels.swift (modified, +214/-0)
  • apps/shared/OpenClawKit/Sources/OpenClawProtocol/GatewayModels.swift (modified, +214/-0)
  • docs/concepts/openclaw-sdk.md (modified, +12/-5)
  • packages/sdk/src/client.ts (modified, +13/-9)
  • packages/sdk/src/index.e2e.test.ts (modified, +54/-0)
  • packages/sdk/src/index.test.ts (modified, +64/-9)
  • packages/sdk/src/index.ts (modified, +6/-0)
  • packages/sdk/src/types.ts (modified, +50/-0)
  • src/gateway/method-scopes.test.ts (modified, +3/-0)
  • src/gateway/method-scopes.ts (modified, +3/-0)
  • src/gateway/protocol/index.test.ts (modified, +21/-0)
  • src/gateway/protocol/index.ts (modified, +31/-0)
  • src/gateway/protocol/schema.ts (modified, +1/-0)
  • src/gateway/protocol/schema/protocol-schemas.ts (modified, +16/-0)
  • src/gateway/protocol/schema/tasks.ts (added, +91/-0)
  • src/gateway/protocol/schema/types.ts (modified, +7/-0)
  • src/gateway/server-methods-list.ts (modified, +3/-0)
  • src/gateway/server-methods.ts (modified, +2/-0)
  • src/gateway/server-methods/tasks.test.ts (added, +167/-0)
  • src/gateway/server-methods/tasks.ts (added, +205/-0)
  • src/tasks/detached-task-runtime-contract.ts (modified, +1/-0)
  • src/tasks/task-registry.ts (modified, +5/-2)

PR #74849: fix: stabilize SDK chat projection deltas and abort/wait snapshot durability

Description (problem / solution / changelog)

Two bugs surfaced by ClawSweeper commit review against the dogfood SDK stabilization work. Both affect app-client state correctness: one causes duplicated assistant text, the other allows a cancel outcome to be silently overwritten by a late completion.

Summary

  • Problem 1: normalizeChatProjectionEvent() emitted the full buffered snapshot as data.delta for every chat projection frame. Clients appending event.data.delta (as documented) duplicated all text after the first chunk.
  • Problem 2: An RPC cancel (sessions.abort) write snapshot could be overwritten by a late dispatchAgentRunFromGateway completion, flipping app state from cancelled back to completed/ok — recreating the cancel/wait disagreement the parent issue was fixing.
  • What changed: incremental delta emission in SDK per-run streams; abortedRuns marker durability through lifecycle cleanup; dedupe guard that makes RPC cancel snapshots authoritative; aborted result/rejection paths map to timeout not ok/error.
  • What did NOT change: canonical agent-stream event handling, non-abort error paths, unrelated dedupe/wait logic.

Fix 1 — packages/sdk/src/client.ts

Track previousChatProjectionText per run stream. Emit incremental chunks:

// Before
{ delta: text }  // full accumulated text every frame

// After
{ text, delta: text.slice(previousText.length) }          // extending append
{ text, delta: text, replace: true }                       // non-extending reset

Fix 2 — Gateway abort/wait durability (three files)

src/gateway/server-chat.ts: Remove chatRunState.abortedRuns.delete() from the terminal lifecycle finalizer — aborted markers must survive cleanup so the chat.send completion guard stays valid.

src/gateway/server-methods/agent-wait-dedupe.ts: setGatewayDedupeEntry() now refuses to overwrite an existing { status: timeout, stopReason: rpc } entry with any later write. Cancel snapshots are terminal and authoritative.

src/gateway/server-methods/agent.ts: dispatchAgentRunFromGateway() maps result.meta.aborted === true and AbortError rejections to { status: "timeout", stopReason: "rpc" } instead of "ok"/"error". The dedupe guard is populated before any late-completion race can arrive.

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

  • Related #74704
  • Related #74827
  • Related #74830
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause (Fix 1): Gateway chat projection payloads carry the full accumulated text (mergedText), not an incremental delta. The SDK normalizer assumed the payload was already incremental.
  • Root cause (Fix 2): dispatchAgentRunFromGateway unconditionally wrote status: "ok" on completion and status: "error" on rejection, regardless of abort state. The lifecycle finalizer also cleared the abortedRuns marker, letting the chat.send completion guard go false before the underlying send settled. Combined, a later agent.wait call could observe ok or error for a cancelled run.
  • Missing detection / guardrail: No test covered a second agent.wait call after the underlying run promise settled post-abort.
  • Contributing context: The abort/wait alignment landed in #74751 but did not guard against the race between sessions.abort's dedupe write and the async completion handler's later write.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Fix 1packages/sdk/src/index.test.ts: adds a non-extending reset frame and asserts { text, delta: " again" } / { text, delta: "reset", replace: true } shapes.
  • Fix 2asrc/gateway/server-chat.agent-events.test.ts: asserts abortedRuns marker survives a terminal lifecycle event.
  • Fix 2bsrc/gateway/server-methods/agent-wait-dedupe.test.ts: two new cases assert that a later ok or error entry cannot overwrite an existing { timeout, stopReason: rpc } entry.
  • Fix 2csrc/gateway/server-methods/agent.test.ts: updates two existing aborted-run tests to assert dedupe payload is { status: "timeout" }; adds an integration test that aborts a live run, writes the cancel snapshot, lets the deferred completion resolve, and asserts the cancel snapshot wins.

User-visible / Behavior Changes

  • SDK Run.events() for chat-only streams: assistant.delta events now carry data.delta as an incremental chunk (not the full accumulated text). Clients using data.delta for streaming UI will no longer duplicate text. data.text carries the full accumulated snapshot for clients that prefer it.
  • Run.cancel() / sessions.abort result is now durable: a subsequent run.wait() after cancellation will not flip to completed or failed if the underlying runner drains after the abort.

Diagram (if applicable)

Before (chat-only delta):
frame 1: text="hello"       → data.delta="hello"
frame 2: text="hello world" → data.delta="hello world"  ← duplicate

After:
frame 1: text="hello"       → data.delta="hello"
frame 2: text="hello world" → data.delta=" world"
frame 3: text="reset"       → data.delta="reset", replace:true

Before (abort race):
sessions.abort → dedupe[agent:runId] = { timeout, stopReason:rpc }
runner drains  → dedupe[agent:runId] = { ok }   ← overwrites cancel
agent.wait     → status: "completed"            ← wrong

After:
sessions.abort → dedupe[agent:runId] = { timeout, stopReason:rpc }
runner drains  → setGatewayDedupeEntry skips write (rpc cancel is authoritative)
agent.wait     → status: "cancelled"            ← correct

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: Linux (CI)
  • Runtime/container: Node 22
  • Model/provider: N/A (unit/integration tests)
  • Integration/channel: N/A
  • Relevant config: N/A

Steps

  1. Run pnpm test packages/sdk/src/index.test.ts — all 14 tests pass including the updated chat-only delta assertions.
  2. Run pnpm test src/gateway/server-methods/agent-wait-dedupe.test.ts — 10 tests pass, including two new cancel-wins cases.
  3. Run pnpm test src/gateway/server-chat.agent-events.test.ts — 53 tests pass, including the new abortedRuns durability case.
  4. Run pnpm test src/gateway/server-methods/agent.test.ts — 80 tests pass, including the new integration test for abort-snapshot-wins.

Expected

  • All targeted tests pass.
  • Chat projection deltas are incremental.
  • Cancel snapshot survives late completion.

Actual

  • All 4 test suites pass.

Evidence

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

All 4 test suites green after changes; behavior assertions changed from full-snapshot to incremental-delta and from ok/error-wins to cancel-wins.

Human Verification (required)

  • Verified scenarios: unit and integration test suites covering all three regression paths run clean.
  • Edge cases checked: non-extending (replacement) chat delta, AbortError rejection path, dedupe key with no waiter, abortedRuns marker after lifecycle cleanup.
  • What you did not verify: live Gateway round-trip against a real runner; Windows-specific timer behavior.

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 — data.text is additive; existing consumers using data.delta get correct incremental chunks instead of duplicated full snapshots.
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

  • Risk: SDK consumers that relied on data.delta being the full accumulated text (treating it as a snapshot rather than a delta) will now see only the incremental chunk.
    • Mitigation: data.text is now always present alongside data.delta for chat-projection events, so consumers can migrate to data.text if they need the full snapshot. This matches canonical agent-stream event shape.
  • Risk: setGatewayDedupeEntry's cancel-wins guard blocks all future writes for the same key, including legitimate retries.
    • Mitigation: The guard only activates on { status: timeout, stopReason: rpc } — a narrow RPC-cancel shape. Normal timeout (no stopReason) and error entries are unaffected. Idempotency key reuse across separate runs is not a supported pattern.

Changed files

  • packages/sdk/src/client.ts (modified, +21/-3)
  • packages/sdk/src/index.test.ts (modified, +31/-7)
  • src/gateway/server-chat.agent-events.test.ts (modified, +21/-0)
  • src/gateway/server-chat.ts (modified, +0/-2)
  • src/gateway/server-methods/agent-wait-dedupe.test.ts (modified, +65/-0)
  • src/gateway/server-methods/agent-wait-dedupe.ts (modified, +7/-2)
  • src/gateway/server-methods/agent.test.ts (modified, +80/-2)
  • src/gateway/server-methods/agent.ts (modified, +14/-9)
RAW_BUFFERClick to expand / collapse

Goal

Stabilize the current @openclaw/sdk happy path for real external app clients.

OpenMeow is a useful dogfood client because it exercises the core app-SDK flow without requiring future managed/cloud features.

Happy path to validate

  1. Connect to Gateway.
  2. Discover agents/models.
  3. Create or resume a session.
  4. Send a run.
  5. Stream normalized events.
  6. Wait for a result.
  7. Cancel/stop an active run.
  8. Surface approvals.

Acceptance criteria

  • SDK APIs for agents/sessions/runs are documented as supported today.
  • Run.wait() semantics clearly distinguish wait deadline from runtime timeout.
  • Run.cancel() has reliable identifiers and result semantics for UI clients.
  • Normalized run events are stable enough for app UI state.
  • Unsupported future fields continue to throw explicit unsupported errors.

Dogfood packet

extent analysis

TL;DR

Review and refine the @openclaw/sdk APIs for agents, sessions, and runs to ensure they are well-documented and meet the acceptance criteria for a stable happy path.

Guidance

  • Review the SDK documentation to ensure it accurately reflects the currently supported APIs for agents, sessions, and runs.
  • Verify that the Run.wait() and Run.cancel() methods have clear and consistent semantics, including distinction between wait deadline and runtime timeout.
  • Test the normalized run events to ensure they are stable and suitable for app UI state management.
  • Implement explicit error handling for unsupported future fields to prevent unexpected behavior.

Example

No code snippet is provided as the issue does not contain specific code references.

Notes

The provided information lacks specific technical details, so the guidance is focused on reviewing and refining the existing SDK APIs and documentation.

Recommendation

Apply workaround: Refine the @openclaw/sdk APIs and documentation to meet the acceptance criteria, as a stable happy path is crucial for real external app clients.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix SDK: stabilize app-client happy path for agents, sessions, runs [10 pull requests, 6 comments, 4 participants]