Skip to content

feat(runtime): surface cost, usage breakdown, and available commands on status events and getStatus#345

Merged
steipete merged 9 commits into
openclaw:mainfrom
DaniAkash:feature/runtime-usage-and-commands-on-status
May 29, 2026
Merged

feat(runtime): surface cost, usage breakdown, and available commands on status events and getStatus#345
steipete merged 9 commits into
openclaw:mainfrom
DaniAkash:feature/runtime-usage-and-commands-on-status

Conversation

@DaniAkash

@DaniAkash DaniAkash commented May 25, 2026

Copy link
Copy Markdown
Contributor

Surfaces fields the wire protocol already carries but the runtime currently throws away. Pure addition — every new field is optional and existing event shapes are preserved.

Motivation

Downstream consumers building chat UIs on top of acpx can't render a live context-window bar or detect agent-advertised slash commands today, because the runtime drops the relevant data on the floor between the wire payload and the public event/status surfaces.

  • usage_update: ACP carries cost, plus a per-turn token breakdown under _meta.usage (Claude Code populates this; Codex partially does). The runtime currently keeps only used and size.
  • available_commands_update: ACP carries AvailableCommand[] with name/description/input. The runtime currently emits a one-line summary string and discards the list.
  • getStatus(): the session reducer already persists cumulative_token_usage, request_token_usage, and acpx.available_commands onto the record, but the public AcpRuntimeStatus shape doesn't expose any of them.

This PR plumbs all three through.

What changed

src/runtime/public/contract.ts

New types:

  • AcpRuntimeUsageCost = { amount?, currency? }
  • AcpRuntimeUsageBreakdown = { inputTokens?, outputTokens?, cachedReadTokens?, cachedWriteTokens?, thoughtTokens?, totalTokens? }
  • AcpRuntimeAvailableCommand = { name, description?, hasInput }
  • AcpRuntimeSessionUsage = { cumulative?, perRequest? }

Extends the status variant of AcpRuntimeEvent with optional cost, breakdown, availableCommands. Extends AcpRuntimeStatus with optional usage, availableCommands.

src/runtime/public/events.ts

  • usageUpdateEvent now reads payload.cost and payload._meta.usage defensively, normalizes both, and forwards them on the event. Both fields are optional and absent for adapters (e.g. gemini-cli today) that don't report them.
  • New availableCommandsUpdateEvent replaces the previous one-line-summary mapping. Normalizes each entry into { name, description?, hasInput }, dropping entries that lack a usable name. The wire input payload (an AvailableCommandInput schema) is intentionally collapsed into the hasInput boolean — picker UIs only need the binary "does it want an argument?" signal, and we don't want to lock in the input schema here.

src/runtime/engine/manager.ts

  • getStatus() now includes usage and availableCommands when the persisted record carries the underlying data. The session reducer already stashes both, so no reducer changes are needed.
  • New helpers tokenUsageToBreakdown, buildUsageField, buildAvailableCommandsField next to the existing buildModelsField.

The persisted record format (SessionTokenUsage uses snake_case + Claude-style key names; the reducer at conversation-model.ts:421 only retains 4 of the 6 SDK token fields) is preserved as-is. tokenUsageToBreakdown maps:

persisted (snake_case) runtime (camelCase)
input_tokens inputTokens
output_tokens outputTokens
cache_read_input_tokens cachedReadTokens
cache_creation_input_tokens cachedWriteTokens

thoughtTokens and totalTokens aren't persisted today (only seen on live events from _meta.usage). Live events from the new event path carry the full 6-field shape; status reads from the persisted record carry the 4-field subset. The asymmetry is documented in the type doc-comments.

buildAvailableCommandsField reads names from record.acpx.available_commands (which the reducer persists as string[]) and surfaces them as { name, hasInput: false }. Live events from the new event path carry the richer { name, description, hasInput } shape. Same asymmetry, same reason — kept the reducer's persisted shape untouched to avoid a session-record migration.

Tests

  • test/runtime-events.test.ts — new tests for usage_update with cost + _meta.usage round-trip, partial-cost handling, _meta without a usage record being ignored, and availableCommands enrichment (description, hasInput flag, dropped invalid entries). Existing tests updated to feed the realistic object form (the old test fed bare strings — non-spec).
  • test/runtime-manager.test.ts — new tests covering getStatus() populating both fields when the record carries them, and omitting both when the record is empty.

CHANGELOG.md

Three bullets under "Unreleased / Changes". No breaking entries.

Test plan

  • pnpm typecheck clean.
  • pnpm lint clean.
  • pnpm format:check clean (against tracked files; the coverage/ and reports/ artifacts that pnpm check produces are pre-existing repo behavior, not from this PR).
  • pnpm test — 734 / 734 pass, 0 fail.
  • pnpm check (format → typecheck → lint → build → viewer:typecheck → viewer:build → test:coverage → mutate) runs end-to-end with mutation score 91.07 ≥ 80 threshold.

Compatibility

  • All-additive. Every new field on the public contract is optional. Existing consumers that read only used / size from usage_update, or read only the existing fields on AcpRuntimeStatus, continue to work unchanged.
  • The text payload on the available_commands_update event changes from "available commands updated (N)" (or "available commands updated" for empty/missing list) to always include a count — "available commands updated (N)" with N >= 0. The two test cases that pinned the old text have been updated.
  • Persisted record schema unchanged.

Out of scope (deliberate)

  • The AvailableCommandInput schema isn't plumbed through — we only surface hasInput: boolean. If/when picker UIs need typed input args, that's a separate addition.
  • Compaction itself is intentionally not added to the runtime. Compaction stays client-initiated as a regular slash-command prompt — the agent (Claude Code / Codex) interprets it on its side; the runtime stays out of the way. Downstream consumers can build a compact() convenience on top of the new event channel by sending the agent's reported /compact name as a startTurn text.
  • The session reducer continues to persist only command names (not descriptions or hasInput). That's why getStatus().availableCommands carries description = undefined, hasInput = false for entries sourced from the persisted record, while live events from the wire carry the full data. Migrating the persisted shape is a follow-up if downstream consumers need historical detail.
Real-agent verification (click to expand)

What was tested

A minimal harness that exercises every new surface this PR adds and
dumps the result as JSON. The full script is reproducible from a clean
checkout of this branch with pnpm install && pnpm build, then node proof.mjs with the file below.

// proof.mjs — verifies the new fields end-to-end against any
// ACP-compatible agent the runtime's built-in registry knows about.
// Change the `agent` value below to point at a different adapter.
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import {
  createAcpRuntime,
  createAgentRegistry,
  createFileSessionStore,
} from "./dist/runtime.js";

const stateDir = mkdtempSync(join(tmpdir(), "acpx-proof-"));
const cwd = mkdtempSync(join(tmpdir(), "acpx-proof-cwd-"));

const runtime = createAcpRuntime({
  cwd,
  sessionStore: createFileSessionStore({ stateDir }),
  agentRegistry: createAgentRegistry(),
  permissionMode: "approve-reads",
  nonInteractivePermissions: "deny",
  timeoutMs: 120_000,
});

const events = [];
try {
  const handle = await runtime.ensureSession({
    sessionKey: "proof",
    agent: "codex", // change to "claude" or "gemini" to exercise other adapters
    mode: "persistent",
    cwd,
  });
  const turn = runtime.startTurn({
    handle,
    text: "Respond with exactly the word 'pong' and nothing else.",
    mode: "prompt",
    requestId: "proof-req-1",
    timeoutMs: 120_000,
  });
  for await (const ev of turn.events) events.push(ev);
  const result = await turn.result;
  const status = await runtime.getStatus({ handle });

  const usage = events.filter((e) => e.type === "status" && e.tag === "usage_update");
  const cmds = events.filter((e) => e.type === "status" && e.tag === "available_commands_update");

  console.log(JSON.stringify({
    turnResult: result,
    usageUpdateEventCount: usage.length,
    usageUpdateEventFirst: usage[0],
    availableCommandsUpdateEventCount: cmds.length,
    availableCommandsUpdateEvents: cmds,
    getStatusResponse: status,
  }, null, 2));

  try { await runtime.close({ handle, reason: "proof done" }); } catch {}
} finally {
  rmSync(stateDir, { recursive: true, force: true });
  rmSync(cwd, { recursive: true, force: true });
}

Captured output (codex, redacted)

Ran against npx -y @agentclientprotocol/codex-acp@^0.0.44
(resolved by the runtime's built-in registry under agent: "codex"),
local codex CLI authenticated via ChatGPT. Session UUIDs, pids,
tmpdir paths, and locally-installed skill names have been redacted;
the four codex built-in commands (mcp, skills, status, logout)
are kept verbatim as they are part of codex's public command surface.

{
  "turnResult": { "status": "completed", "stopReason": "end_turn" },
  "usageUpdateEventCount": 1,
  "usageUpdateEventFirst": {
    "type": "status",
    "text": "usage updated: 19985/258400",
    "tag": "usage_update",
    "used": 19985,
    "size": 258400
  },
  "availableCommandsUpdateEventCount": 1,
  "availableCommandsUpdateEvents": [
    {
      "type": "status",
      "text": "available commands updated (38)",
      "tag": "available_commands_update",
      "availableCommands": [
        { "name": "mcp",    "description": "List configured Model Context Protocol (MCP) tools.", "hasInput": false },
        { "name": "skills", "description": "List available skills.",                              "hasInput": false },
        { "name": "status", "description": "Display session configuration and token usage.",      "hasInput": false },
        { "name": "logout", "description": "Sign out of Codex...",                                "hasInput": false },
        { "name": "$<redacted-local-skill>", "description": "<truncated>", "hasInput": false },
        { "name": "$<redacted-local-skill>", "description": "<truncated>", "hasInput": false },
        { "_redacted": "32 additional locally-installed skills omitted" }
      ]
    }
  ],
  "getStatusResponse": {
    "summary": "session=proof backendSessionId=<redacted> pid=<redacted> open",
    "models": {
      "currentModelId": "gpt-5.5[medium]",
      "availableModelIds": [
        "gpt-5.5[low]", "gpt-5.5[medium]", "gpt-5.5[high]", "gpt-5.5[xhigh]",
        "gpt-5.4[low]", "gpt-5.4[medium]", "gpt-5.4[high]", "gpt-5.4[xhigh]",
        "gpt-5.4-mini[low]", "...", "gpt-5.2[xhigh]"
      ]
    },
    "availableCommands": [
      { "name": "mcp",    "hasInput": false },
      { "name": "skills", "hasInput": false },
      { "name": "status", "hasInput": false },
      { "name": "logout", "hasInput": false },
      { "_redacted": "34 locally-installed skills omitted" }
    ],
    "details": { "cwd": "<redacted-tmpdir>", "lastUsedAt": "...", "closed": false }
  }
}

What this validates

New surface Codex result Verdict
available_commands_update.availableCommands rich list (the previously-dropped field) 38 entries, full { name, description, hasInput } ✅ end-to-end wire-to-runtime plumbing works
AcpRuntimeStatus.availableCommands on getStatus() 38 entries from persisted record, degraded to { name, hasInput: false } as the reducer only persists names ✅ matches the documented behavior
usage_update.used / usage_update.size (preserved) 19985 / 258400 ✅ no regression on the existing fields
Legacy available_commands_update fallback text when list is empty n/a in this capture (codex sends a non-empty list); covered by unit test parsePromptEventLine covers status and tool summary fallbacks
usage_update.cost absent from this codex run — adapter doesn't emit it ✅ normalizer defensively omits the field; used/size-only consumers see no change
usage_update.breakdown absent from this codex run — codex doesn't populate _meta.usage ✅ same defensive-omit; unit test parsePromptEventLine surfaces cost and _meta.usage breakdown on usage_update covers the populated case
AcpRuntimeStatus.usage absent because the reducer had no _meta.usage to persist ✅ field omitted cleanly when empty

The two new payload surfaces this PR adds (rich availableCommands on
the event and on getStatus()) both round-trip correctly against a
real codex turn. The two surfaces codex doesn't emit (cost,
breakdown) demonstrate the normalizer's defensive-omit behavior —
the runtime never fabricates empty objects, so consumers that read
only used/size see byte-identical events to main.

How this generalises to other agents

The harness is agent-neutral — only the agent: "codex" string
changes when pointing at a different adapter. Same script, same
assertions, just a different built-in spawn command resolved by the
agent registry.

  • Claude (@agentclientprotocol/claude-agent-acp) — Claude Code
    populates _meta.usage per-turn, so the same proof against
    agent: "claude" will surface usage_update.breakdown populated
    with inputTokens / outputTokens / cachedReadTokens / cachedWriteTokens / thoughtTokens / totalTokens. The cost field is also expected if
    the adapter emits it. The availableCommands list is shorter
    (Claude Code's command set) but the shape is identical.
  • Gemini (gemini --acp) — gemini-cli today doesn't implement
    available_commands_update or usage_update with rich payloads.
    The runtime correctly emits zero events on those surfaces and
    getStatus().availableCommands / getStatus().usage are both
    omitted. No crash, no synthetic empty payloads.
  • Any future adapter that follows the ACP wire spec for
    UsageUpdate and AvailableCommandsUpdate automatically benefits
    from the same plumbing — the changes are wire-level normalizers,
    not adapter-specific code paths.

Reviewers wanting to verify against a different adapter can drop in
their own agent: string (any name the built-in registry resolves) or
register a custom command via createAgentRegistry({ overrides: { ... } }).

@DaniAkash
DaniAkash requested a review from a team as a code owner May 25, 2026 19:05
@clawsweeper

clawsweeper Bot commented May 25, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs real behavior proof before merge. Reviewed May 28, 2026, 8:41 PM ET / 00:41 UTC.

Summary
The PR adds optional runtime status/event fields for usage cost, token breakdowns, and available commands, persists richer usage/command metadata, updates replay-viewer/runtime helpers, and adds runtime/session tests.

Reproducibility: not applicable. this is an additive runtime API feature PR rather than a bug report. Current-main source inspection confirms the requested public usage and command fields are not present today.

Review metrics: 3 noteworthy metrics.

  • Diff scope: 19 files, +809/-22. The patch spans runtime contracts, event parsing, session persistence, replay-viewer types, tests, and release text, so compatibility review matters more than a tiny patch review.
  • Public runtime surface: 4 exported types and 5 optional runtime fields added. New event/status names become part of the embedding API that downstream consumers may rely on.
  • Real proof coverage: availableCommands shown; cost, breakdown, and status usage absent. The live Codex capture proves one major surface but leaves the usage metadata paths as unit-test-only or adapter-claim evidence.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦐 gold shrimp
Patch quality: 🦐 gold shrimp
Result: blocked until stronger real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Make the persisted command compatibility path explicit with docs/tests or preserve the existing string[] session-record shape.
  • Remove the direct CHANGELOG.md edit from the feature branch.
  • [P1] Add redacted live output for populated usage/cost metadata or get an explicit maintainer waiver for that surface.

Proof guidance:

  • [P1] Needs stronger real behavior proof before merge: The PR body includes redacted live Codex output for availableCommands, but populated cost, breakdown, and getStatus().usage are not shown; add redacted terminal/log proof from an adapter that emits usage metadata or get an explicit maintainer waiver. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Risk before merge

  • [P1] The PR writes object-valued acpx.available_commands under the existing acpx.session.v1 schema while the existing session model docs still show string arrays; downstream session-file readers could see a silent shape change unless maintainers explicitly accept and document the union.
  • [P1] The real-agent proof demonstrates availableCommands, but populated cost, breakdown, and getStatus().usage remain unproven in live output from an adapter that emits usage metadata.
  • [P1] The branch still contains a direct CHANGELOG.md release-note edit, which should be removed from a normal feature PR under the OpenClaw review policy.

Maintainer options:

  1. Make session-record compatibility explicit (recommended)
    Before merge, either keep acpx.available_commands serialized as string names or document and test the v1 union plus legacy string-record loading and downstream-facing behavior.
  2. Accept the v1 shape expansion
    Maintainers can intentionally accept object-valued commands under acpx.session.v1 if they are comfortable with downstream session-file readers seeing the new shape.
  3. Wait for complete adapter proof
    Pause landing until real adapter output or an explicit waiver covers populated cost, breakdown, and status usage, not only available commands.

Next step before merge

  • [P1] Human review should decide the stable runtime API and persisted session-record compatibility path; automation cannot supply the missing real-adapter usage proof.

Security
Cleared: The diff changes runtime TypeScript, tests, replay-viewer types, and changelog text; it does not add dependencies, workflows, scripts, secret handling, or publishing changes.

Review findings

  • [P2] Make the session-record format change explicit — src/types.ts:361
  • [P3] Remove the direct changelog edit — CHANGELOG.md:12
Review details

Best possible solution:

Land a refreshed PR that either preserves or explicitly documents/tests the v1 session-record command shape, removes release-owned changelog text, and includes redacted live usage proof or a maintainer waiver for adapter metadata that cannot be emitted in the contributor setup.

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

Not applicable: this is an additive runtime API feature PR rather than a bug report. Current-main source inspection confirms the requested public usage and command fields are not present today.

Is this the best way to solve the issue?

Unclear: the event/status plumbing is narrow, but the persisted session-record shape and stable public field names need explicit maintainer acceptance, and the proof still does not show populated usage metadata from a real adapter.

Full review comments:

  • [P2] Make the session-record format change explicit — src/types.ts:361
    Changing available_commands from the documented v1 string[] to SessionAvailableCommand[] means new session files serialize a different shape while SESSION_RECORD_SCHEMA remains acpx.session.v1 and the session model doc still shows strings. Please either keep the persisted field as string names or update the compatibility contract, tests, and docs for the v1 union before merge.
    Confidence: 0.82
  • [P3] Remove the direct changelog edit — CHANGELOG.md:12
    OpenClaw's release-note lane owns CHANGELOG.md; normal feature PRs should leave release text out of the branch. Drop this line and keep release-note context in the PR body or commit message instead.
    Confidence: 0.9

Overall correctness: patch is incorrect
Overall confidence: 0.82

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

  • add merge-risk: 🚨 compatibility: The PR changes the persisted acpx.available_commands shape under the existing v1 session schema, which could surprise existing session-file consumers.

Label justifications:

  • P2: This is a normal-priority runtime API improvement with limited blast radius but real downstream value and compatibility details to settle before merge.
  • merge-risk: 🚨 compatibility: The PR changes the persisted acpx.available_commands shape under the existing v1 session schema, which could surprise existing session-file consumers.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦐 gold shrimp and patch quality is 🦐 gold shrimp.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs stronger real behavior proof before merge: The PR body includes redacted live Codex output for availableCommands, but populated cost, breakdown, and getStatus().usage are not shown; add redacted terminal/log proof from an adapter that emits usage metadata or get an explicit maintainer waiver. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed

What I checked:

  • AGENTS.md policy applied: AGENTS.md was read fully; its product-direction guidance says data models and output shapes are product surface with long-term compatibility cost, which applies to the new runtime fields and persisted command shape. (AGENTS.md:41, 8fe06d91a718)
  • Current main lacks requested runtime fields: On current main, AcpRuntimeStatus exposes models/details but no usage or availableCommands, and status events expose only used/size for usage updates. (src/runtime/public/contract.ts:91, 8fe06d91a718)
  • PR changes persisted command shape under v1 schema: The PR head keeps SESSION_RECORD_SCHEMA as acpx.session.v1 while changing acpx.available_commands from string[] to SessionAvailableCommand[]. (src/types.ts:361, 6c1b24ae2891)
  • Legacy parser support exists but docs remain old-shape: The PR parser accepts both legacy strings and command objects, while the existing session model document still describes available_commands as a string array. (src/session/persistence/parse.ts:26, 6c1b24ae2891)
  • Session model doc still shows string commands: The in-repo session model reference shows acpx.available_commands as an array of strings, so the new object-valued write path is not documented there. (docs/2026-02-27-acpx-session-model.md:124, 8fe06d91a718)
  • Real-agent proof is partial: The PR body includes redacted live Codex output showing availableCommands on an event and getStatus(), but cost, breakdown, and getStatus().usage are absent in that capture and covered only by unit tests or adapter claims. (6c1b24ae2891)

Likely related people:

  • DaniAkash: A prior merged commit by Dani Akash added getStatus model exposure in the same runtime contract/manager surface this PR extends, so they are a relevant routing candidate beyond being the PR author. (role: recent runtime public-surface contributor; confidence: high; commits: b76a80bf9fe9; files: src/runtime/public/contract.ts, src/runtime/engine/manager.ts, test/runtime-manager.test.ts)
  • osolmaz: GitHub commit history identifies the runtime embedding API work that introduced the contract, events, and manager surfaces touched by this PR. (role: introduced runtime API surface; confidence: high; commits: be510ba918d4; files: src/runtime/public/contract.ts, src/runtime/public/events.ts, src/runtime/engine/manager.ts)
  • steipete: The current PR head includes several steipete-authored commits in the runtime/session metadata path, and current-main blame for the central files maps to Peter Steinberger's release commit in this checkout. (role: recent adjacent area contributor; confidence: medium; commits: 00e4c9452290, 5aea379ef653, f905568400d5; files: src/runtime/public/events.ts, src/runtime/engine/manager.ts, src/session/conversation-model.ts)
  • mvanhorn: Recent session export/import work touched session persistence/types, which are adjacent to this PR's persisted session-record changes. (role: recent session persistence contributor; confidence: medium; commits: 1dfbcf67dcf3; files: src/session/persistence/parse.ts, src/types.ts, test/session-export-import.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels May 25, 2026
@clawsweeper

clawsweeper Bot commented May 25, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🎁 Pass real behavior proof to wake the egg and unlock a hatchable treat.

Where did the egg go?
  • The egg game starts only after the PR passes the real-behavior proof check.
  • Before that, no creature or rarity is rolled. The treat waits for real proof.
  • This is still just collectible flavor: proof affects review readiness, not creature quality.

@clawsweeper clawsweeper Bot added the P2 Normal priority bug or improvement with limited blast radius. label May 26, 2026
@DaniAkash

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Added a folded "Real-agent verification" section to the PR description with the harness script, redacted codex output, and a field-by-field validation matrix covering each new surface and how it generalises to other adapters.

@clawsweeper

clawsweeper Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels May 26, 2026
DaniAkash and others added 9 commits May 29, 2026 01:04
…on status events and getStatus

The ACP wire protocol carries richer context-window and command data
than the runtime currently exposes. Three additive surface changes:

- usage_update events now carry the agent-reported cost and a typed
  per-turn breakdown (input/output/cachedRead/cachedWrite/thought/total
  tokens) normalized from the wire payload's _meta.usage. Previously
  only the top-level used and size numbers survived into AcpRuntimeEvent.
- available_commands_update events now carry the full availableCommands
  list (name, description, hasInput flag) instead of dropping it to a
  one-line summary, so clients can detect /compact, /clear, and similar
  agent-advertised commands.
- AcpRuntimeStatus.usage and AcpRuntimeStatus.availableCommands now
  expose the cumulative + per-request token breakdowns and command list
  that the session reducer already persists onto the record.

Pure addition: every new field on the AcpRuntimeEvent status variant
and on AcpRuntimeStatus is optional. The text payloads on the existing
events are unchanged for the empty / unknown cases, and the persisted
record schema is untouched.

New types: AcpRuntimeUsageCost, AcpRuntimeUsageBreakdown,
AcpRuntimeAvailableCommand, AcpRuntimeSessionUsage.
… and drop CHANGELOG edit

Two follow-ups from ClawSweeper's review:

- Restore the legacy 'available commands updated' (no count) text when the
  wire list is missing or empty. The structured availableCommands: [] field
  is still attached either way, so text-matching consumers see no change
  while structured consumers still get the new field.
- Revert the direct CHANGELOG.md edit. Feature PRs in this repo leave
  release-note authoring to the release commit by convention.
Add AcpRuntimeAvailableCommand, AcpRuntimeUsageBreakdown,
AcpRuntimeUsageCost, and AcpRuntimeSessionUsage to the export type {}
block in src/runtime.ts so downstream consumers can reach them via
'acpx/runtime' alongside the existing types. Without this they were
declared in contract.ts but only reachable via the deeper
'acpx/runtime/public/contract' import path.
@steipete
steipete force-pushed the feature/runtime-usage-and-commands-on-status branch from b73e05d to 6c1b24a Compare May 29, 2026 00:34
@clawsweeper clawsweeper Bot added the merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. label May 29, 2026
@steipete
steipete merged commit f6de6dd into openclaw:main May 29, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P2 Normal priority bug or improvement with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants