Skip to content

Add OpenClaw provider#103

Open
bcchew-art wants to merge 2 commits intogetagentseal:mainfrom
bcchew-art:feat/openclaw-provider
Open

Add OpenClaw provider#103
bcchew-art wants to merge 2 commits intogetagentseal:mainfrom
bcchew-art:feat/openclaw-provider

Conversation

@bcchew-art
Copy link
Copy Markdown

Summary

Adds a new openclaw provider so codeburn can track usage across OpenClaw multi-agent orchestration sessions. OpenClaw writes JSONL session files per satellite agent in a format very similar to Claude Code's, but with a slightly different usage schema (usage.input/usage.output instead of input_tokens/output_tokens).

Each satellite directory under ~/.openclaw/agents/ becomes a project in the dashboard:

  • main, douyun, etc. — paid API agents (GPT-5.4, Kimi K2.5) priced via LiteLLM
  • ivy, lilith — local Ollama agents (Qwen family) pinned to $0

How it works

  • discoverSessions() enumerates ~/.openclaw/agents/*/sessions/*.jsonl (override via OPENCLAW_AGENTS_DIR), skipping .deleted.* and .reset.* archives.
  • Parser yields one ParsedProviderCall per assistant message with usage.
  • Tool names are mapped to codeburn's canonical set (execBash, readRead, etc.).
  • Local models (api=ollama or model name contains qwen) force $0, even if LiteLLM accidentally matches. Belt-and-suspenders.
  • Non-local models try LiteLLM first, then fall back to the embedded usage.cost.total that OpenClaw records itself. Same fallback pattern as the OpenCode provider.

Test plan

  • npm run build green
  • npx vitest run — 19 files, 256 tests pass (18 new tests in tests/providers/openclaw.test.ts covering discovery, parsing, pricing, display names)
  • codeburn today --provider openclaw shows per-satellite breakdown
  • codeburn today (unified) shows OpenClaw alongside Claude/Codex
  • Qwen models consistently $0 across both the hardcoded model name and variants like qwen3:32b
  • GPT-5.4 and moonshotai/kimi-k2.5 correctly priced via LiteLLM
  • Dedup via openclaw:<sessionId>:<messageId> prevents re-counting across re-runs

Notes

  • New file: src/providers/openclaw.ts (226 lines)
  • Registered in src/providers/index.ts alongside existing core providers
  • Tests: tests/providers/openclaw.test.ts (new), tests/provider-registry.test.ts (1 line updated)
  • No new runtime dependencies
  • Follows the project's CLAUDE.md style guide (no emoji, no em dashes, single quotes, no semicolons, node builtins → deps → local import order)

Happy to iterate on naming, display strings, or the pricing fallback heuristic if you'd prefer a different approach.

Tracks token usage and cost across OpenClaw satellite agents by reading
JSONL session files from ~/.openclaw/agents/*/sessions/. Each satellite
directory becomes a project. Local Ollama models (qwen family) are
pinned to $0 regardless of LiteLLM matches. Paid models route through
the existing LiteLLM pricing, with the session's embedded cost field as
fallback for models not yet in the pricing catalog.

Archived session files (.deleted.*, .reset.*) are skipped during
discovery. Override base directory with OPENCLAW_AGENTS_DIR.
The .deleted.* and .reset.* suffixes are OpenClaw's session rotation
scheme, not user deletion. The data in rotated files is intact and
represents real usage that should be counted. Skipping them caused a
~6x undercount against a representative multi-agent setup.

Safe to include all *.jsonl* files because the dedup key is
sessionId+messageId (content-derived), so any accidental overlap
between a live file and a rotated copy is handled by the existing
seenKeys logic in the parser.

Updated the corresponding test to assert inclusion rather than skip.
@bcchew-art
Copy link
Copy Markdown
Author

Post-review gut-check from one of my own users surfaced a bug I shipped in the first pass. OpenClaw archives session files by renaming them with a .deleted.* or .reset.* suffix rather than actually deleting. My initial provider skipped those as archives — which undercounted real usage by ~6x on a representative setup ($18 → $128 all-time). Pushed b5721e2: include all *.jsonl* files and rely on the existing sessionId+messageId dedup to handle any overlap. Test updated accordingly. All 256 tests still green.

@iamtoruk
Copy link
Copy Markdown
Member

OpenClaw support has been merged in #175. Thanks for the contribution! Would you mind sharing a screenshot of your CodeBurn report?

@Qodo-Free-For-OSS
Copy link
Copy Markdown

Hi, The OpenClaw parser deduplicates by openclaw:${sessionId}:${messageId} where messageId can be empty or repeated across different session files, causing legitimate calls to be silently dropped when seenKeys is shared across all sources.

Severity: action required | Category: correctness

How to fix: Make dedup keys globally unique

Agent prompt to fix - you can give this to your LLM of choice:

Issue description

OpenClaw deduplication keys can collide across different session sources because they don't incorporate the session source identity and can degrade to an empty message id.

Issue Context

seenKeys is shared across all parsed sources for a provider in a single run, so dedup keys must be unique across all session files/projects.

Fix Focus Areas

  • src/providers/openclaw.ts[149-154]
  • src/providers/openclaw.ts[110-111]

Suggested fix

  • Include source.path (or source.project + filename) in the key, similar to other providers.
  • Ensure a non-empty per-line fallback when both entry.id and entry.timestamp are missing (e.g., include the line index in the key).

Spotted by Qodo code review - free for open-source projects.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants