Skip to content

feat(context-engine): add ByteRover context engine plugin#43920

Closed
danhdoan wants to merge 6 commits into
openclaw:mainfrom
danhdoan:feat/byterover-context-engine-plugin
Closed

feat(context-engine): add ByteRover context engine plugin#43920
danhdoan wants to merge 6 commits into
openclaw:mainfrom
danhdoan:feat/byterover-context-engine-plugin

Conversation

@danhdoan

@danhdoan danhdoan commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Problem: OpenClaw's built-in context management (compaction/summarization) is lossy — information is irreversibly compressed when the context window fills up. Agents lose valuable historical knowledge across long conversations.
  • Why it matters: Users expect the agent to remember decisions, preferences, and technical details from earlier turns. A pluggable knowledge layer that persists curated context independently gives the agent long-term memory beyond the context window.
  • What changed: Added ByteRover context engine plugin (extensions/byterover/, 1605 lines) that curates conversation turns via brv curate and retrieves relevant knowledge via brv query, injected as systemPromptAddition. Added optional prompt?: string to the assemble() interface (3 lines in core) so retrieval-augmented engines receive the current query directly. ByteRover provides persistent, stateful, long-term memory for AI agents and enables humans and agents to collaboratively manage project context through intelligent, cutting-edge curation and retrieval.
  • What did NOT change (scope boundary): Zero modifications to existing compaction logic, LegacyContextEngine, message format, or API contracts. No new runtime dependencies in root package.json. The prompt parameter is optional — all existing engines are unaffected.

Change Type

  • Feature

Scope

  • Memory / storage
  • Integrations
  • API / contracts

Linked Issue/PR

User-visible / Behavior Changes

  • New byterover context engine plugin available under extensions/byterover/
  • When enabled, the agent receives curated historical knowledge as part of its system prompt on every turn
  • New optional config fields: brvPath, cwd, queryTimeoutMs, curateTimeoutMs under plugins.entries.byterover.config
  • Requires plugins.slots.contextEngine: "byterover" in ~/.openclaw/openclaw.json
  • Token-saving measures: curation prompt prefix filters trivial messages server-side; short-query gate skips retrieval for queries < 5 chars

Configuration

Enable in ~/.openclaw/openclaw.json:

{
  "plugins": {
    "slots": {
      "contextEngine": "byterover"
    },
    "entries": {
      "byterover": {
        "enabled": true,
        "config": {
          "brvPath": "/path/to/brv",
          "cwd": "/path/to/project-with-brv-initialized"
        }
      }
    }
  }
}

All config fields are optional — brvPath defaults to "brv" (resolved from PATH), cwd defaults to process.cwd(), timeouts have sensible defaults (12s query, 60s curate).

Prerequisites

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No — the plugin spawns a local CLI binary; brv daemon handles its own network communication
  • Command/tool execution surface changed? Yes — spawns brv child processes
  • Data access scope changed? No — context engines already access the same message data that compaction accesses
  • Mitigation: Output capped at 512KB (maxOutputChars) — runBrv kills the child if stdout exceeds limit to prevent memory exhaustion. Process cleanup on abort via AbortSignal + SIGKILL ensures no orphan processes. Metadata stripping prevents untrusted sender metadata from leaking into brv queries. POSIX -- arg terminator prevents user text starting with - from being parsed as CLI flags.

Repro + Verification

Environment

  • OS: macOS 15.5 / macOS 26.2 / Ubuntu 25.10 (kernel 6.17.0-1007-gcp)
  • Runtime/container: Node v22.21.1 / v22.22.1 / v24.13.1
  • Model/provider: Any (context engine is model-agnostic)
  • Integration/channel (if any): Telegram, Discord, Slack (verified), applicable to all channels
  • Relevant config (redacted):
{
  "plugins": {
    "slots": { "contextEngine": "byterover" },
    "entries": { "byterover": { "enabled": true, "config": { "brvPath": "/path/to/brv", "cwd": "/path/to/project" } } }
  }
}

Steps

  1. Install ByteRover CLI
  2. Enable the plugin in openclaw.json as shown above
  3. Start the gateway and send a message via any channel
  4. Observe logs: afterTurn curating N new messagesbrv curate spawned with --detach
  5. Send a follow-up message
  6. Observe logs: assemble querying brvbrv query returns curated knowledge → assemble injecting systemPromptAddition (N chars)
  7. In working folder, context files are curated and stored in .brv folder

Expected

  • afterTurn curates new messages via brv curate --detach (non-blocking, ~ms handshake)
  • assemble retrieves relevant context via brv query and injects it as systemPromptAddition
  • Agent response reflects curated historical knowledge
  • Trivial messages ("ok", "hi") are skipped at both curation and retrieval boundaries
  • Timeouts and errors are handled gracefully — agent proceeds without context rather than failing

Actual

  • All expected behaviors confirmed across 3 platforms (see verification matrix below)

Evidence

Test suite (54 tests, all passing)

pnpm vitest run extensions/byterover/

 ✓ extensions/byterover/brv-process.test.ts (5 tests)
 ✓ extensions/byterover/message-utils.test.ts (17 tests)
 ✓ extensions/byterover/context-engine.test.ts (20 tests)
 ✓ extensions/byterover/context-engine.integration.test.ts (12 tests)

 Test Files  4 passed (4)
      Tests  54 passed (54)
  • Unit tests (context-engine.test.ts, 20 tests): Engine method behavior, message serialization, query extraction, metadata stripping, short-query gate
  • Integration tests (context-engine.integration.test.ts, 12 tests): Full lifecycle with mocked brv process — afterTurn→brvCurate (4), assemble→brvQuery (6+), abort signal handling, error fallback paths
  • NDJSON parser (brv-process.test.ts, 5 tests): Edge cases for JSON line parsing
  • Message utils (message-utils.test.ts, 17 tests): Metadata stripping, sender extraction, assistant tag removal
  • Verified full test suite passes (774/776, 2 pre-existing failures unrelated to this PR).

Platform compatibility & manual verification

Manually verified end-to-end (plugin load → curate → query → context injection) on:

Platform OS Node brv CLI OpenClaw
Linux aarch64 Ubuntu 25.10 (kernel 6.17.0-1007-gcp) v22.22.1 2.1.3 2026.3.8
macOS (Apple Silicon) macOS 26.2 v24.13.1 2.1.3 2026.3.8
macOS (Apple Silicon) macOS 15.5 v22.21.1 2.1.3 2026.3.8

Human Verification (required)

  • Verified scenarios:
    • Full curate → query → injection cycle on 3 platforms (Linux aarch64, macOS 26.2, macOS 15.5)
    • Plugin load and registration via openclaw.plugin.json
    • Timeout handling: agent proceeds without context when brv is slow/unavailable
    • Error recovery: ENOENT when brv is not installed, daemon unreachable, malformed output
    • Short-query gate: trivial messages ("ok", "hi") skip brv spawn
    • Metadata stripping: sender blocks, thread context, reply context all removed before brv
    • Curation prompt prefix: trivial messages filtered server-side
  • Edge cases checked:
    • Messages with only toolResult content (skipped correctly)
    • Empty message arrays and heartbeat turns (no-op)
    • Prompts inflated by metadata that become short after stripping
    • brv output exceeding 512KB cap (child killed)
    • Concurrent abort signal + timer (settled guard prevents double resolve/reject)
  • What I did not verify:
    • Windows platform (brv CLI is not yet available on Windows)
    • x86_64 Linux (only tested aarch64)

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 — the plugin is opt-in. The only core change (prompt?: string on assemble()) is optional and does not affect existing engines.
  • Config/env changes? Yes — new plugins.slots.contextEngine and plugins.entries.byterover config fields. No changes to existing config.
  • Migration needed? No

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: Remove "contextEngine": "byterover" from plugins.slots in openclaw.json, or set "enabled": false on the byterover entry. The runtime falls back to LegacyContextEngine immediately.
  • Files/config to restore: Only ~/.openclaw/openclaw.json — remove the byterover plugin entry.
  • Known bad symptoms reviewers should watch for:
    • assemble brv query timed out warnings in logs — indicates brv daemon is slow or unresponsive
    • ByteRover CLI not found errors — brvPath not set and brv not in gateway's PATH
    • Increased system prompt size — if curation is too aggressive, systemPromptAddition may grow large

Risks and Mitigations

  • Risk: brv child process hangs or orphans on timeout

    • Mitigation: AbortSignal propagation kills child with SIGKILL. Settled guard prevents double resolve/reject. Internal runBrv timeout as fallback for callers that don't pass a signal.
  • Risk: Large systemPromptAddition inflates token usage

    • Mitigation: Curation prompt prefix filters trivial messages server-side. Short-query gate skips retrieval for queries < 5 chars. brv itself controls response size. Future work: add a maxResponseChars config option.
  • Risk: prompt?: string addition to assemble() interface could affect other engines

    • Mitigation: Parameter is optional with no default behavior change. All existing engines (including LegacyContextEngine) ignore it.

Design details (expand for architecture deep-dive)

How it works

Lifecycle mapping

ContextEngine method ByteRover action Behavior
afterTurn brv curate --detach Feeds new conversation turns to the brv daemon for async curation. The CLI exits in ~ms after the daemon acknowledges; the actual curation runs in the background.
assemble brv query Queries the curated knowledge base with the user's prompt. Relevant context is injected as systemPromptAddition (system prompt, not messages — no feedback loop risk).
ingest no-op afterTurn handles batch ingestion of completed turns.
compact delegates to runtime Returns compacted: false with ownsCompaction: false. ByteRover manages knowledge persistence independently through its own curation pipeline — it doesn't need to own OpenClaw's compaction lifecycle. The runtime's built-in auto-compaction handles message-array truncation as usual, while ByteRover's curated knowledge survives independently in its own store.

Data flow

ByteRover operates as a two-phase async pipeline: curation happens in the background after each turn, retrieval happens synchronously before the next turn. This means the agent always has access to curated knowledge from previous turns without any latency penalty on the curation side.

Phase 1 — Retrieval (assemble, synchronous, blocks prompt)

User sends message
  → assemble() receives raw prompt
  → stripUserMetadata(): remove OpenClaw-injected sender/thread/reply metadata blocks
  → short-query gate: skip if cleaned query < 5 chars ("ok", "hi", "y")
  → brv query --format json -- "<clean query>"
    → AbortController deadline (10s) → signal propagates to child process
  → parse NDJSON response → extract result
  → wrap in <byterover-context> → inject as systemPromptAddition
  → agent sees curated knowledge in system prompt, not in messages
     (no feedback loop — won't be re-curated on next turn)

Phase 2 — Curation (afterTurn, async, non-blocking)

Agent completes response
  → afterTurn() receives full message array + prePromptMessageCount
  → slice new messages only (skip pre-existing context)
  → serialize: extract text, strip <final>/<think> tags, attribute senders
     e.g. [Alice @ 2026-03-10T14:30:00Z]: How do hooks work?
          [assistant]: Hooks are lifecycle callbacks that...
  → prepend curation prompt: "Curate only information with lasting value..."
  → brv curate --detach --format json -- "<serialized context>"
    → daemon acknowledges in ~ms, queues actual curation work
    → CLI exits immediately; await captures response + surfaces errors
  → knowledge persists in ByteRover's store, survives compaction and sessions

Key design decisions

  • systemPromptAddition over message injection: Retrieved context goes into the system prompt, not the message array. This avoids feedback loops where injected context would be re-curated on the next turn, and avoids inflating token counts in the message array.

  • Metadata stripping: OpenClaw prepends structured metadata blocks (sender info, thread context, reply context) to user messages. These are stripped before both brv query and brv curate so the CLI receives only substantive content. Sender name/timestamp are extracted and re-attributed cleanly (e.g., [Alice @ 2026-03-10T14:30:00Z]: How do hooks work?).

  • Curation prompt prefix: afterTurn prepends filtering instructions that tell brv to skip trivial messages (greetings, "ok", "thanks") server-side, reducing noise in the knowledge base. This is a deliberate token-saving measure — without it, every "got it" and "sure" would be curated, stored, retrieved on future queries, and injected into the system prompt, burning tokens on noise. By filtering at the curation boundary, we keep the knowledge base lean and reduce systemPromptAddition size on every subsequent assemble call.

  • Short-query gate: assemble skips brv for queries under 5 characters (after metadata stripping) — "ok", "hi", "yes" don't warrant a process spawn or a round-trip to the knowledge base. Same token-saving philosophy as the curation prefix, applied at the retrieval boundary: don't spend tokens retrieving context for queries that won't benefit from it.

  • POSIX -- arg terminator: Both brv query and brv curate use -- before user text to prevent content starting with - from being parsed as CLI flags.

  • AbortSignal cancellation: assemble creates an AbortController with a 10s deadline. The signal propagates through brvQueryrunBrv → child process kill. This replaces a Promise.race pattern and ensures clean process cleanup on timeout.

  • Settled guard: runBrv uses a settled boolean to prevent double resolve/reject from competing event handlers (timer, signal abort, stdout overflow, spawn error, process close). Only the first event settles the promise.

  • Fire-and-forget is a misnomer for --detach: Despite the async nature, we still await the brvCurate call. The --detach flag makes the daemon queue work asynchronously — the CLI itself exits immediately after the handshake (~ms). We await to capture the JSON response (queued status, task ID) and to surface ENOENT/crash errors.

Why prompt? was added to assemble()

The existing assemble() signature only provides the message history — but the incoming user message (the one that triggered this turn) is not yet part of messages at assembly time. For a retrieval-augmented context engine like ByteRover, the current query is the most critical input: it determines what to retrieve. Without it, the engine would have to scan backwards through history and guess which message is the latest user query — fragile and unreliable for multi-turn conversations. This change makes the caller's intent explicit and gives any context engine direct access to the query that matters most. The parameter is optional, so all existing engines are unaffected.

Files changed

New files (plugin — extensions/byterover/)

File Lines Purpose
context-engine.ts 295 ByteRoverContextEngine class implementing the ContextEngine interface
brv-process.ts 241 runBrv spawn wrapper, brvCurate, brvQuery, NDJSON parser
message-utils.ts 191 Metadata stripping, sender extraction, assistant tag removal
index.ts 24 Plugin registration entry point
openclaw.plugin.json 28 Plugin manifest with config schema (brvPath, cwd, timeouts)
package.json 12 Workspace package definition
context-engine.test.ts 257 Unit tests for engine methods, serialization, query extraction
context-engine.integration.test.ts 340 Integration tests with mocked brv (12 tests covering full lifecycle)
brv-process.test.ts 44 Unit tests for NDJSON parsing
message-utils.test.ts 148 Unit tests for metadata stripping and sender extraction

Core changes (minimal, 3 lines)

File Change
src/context-engine/types.ts Add optional prompt?: string parameter to assemble() signature
src/agents/pi-embedded-runner/run/attempt.ts Pass params.prompt through to assemble() call
src/plugin-sdk/byterover.ts Scoped plugin-sdk subpath (re-exports types used by the plugin)
src/plugin-sdk/subpaths.test.ts Add byterover to subpath loader test
package.json Add export map entry for openclaw/plugin-sdk/byterover

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: XL labels Mar 12, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ba829ff7ab

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +145 to +147
const assembleTimeout = this.config.queryTimeoutMs
? Math.min(this.config.queryTimeoutMs, 10_000)
: 10_000;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Honor configured query timeout in assemble

The assemble path clamps queryTimeoutMs to 10s (Math.min(..., 10_000)), so any configured value above 10,000 ms and the documented default behavior in brv-process (12,000 ms) are silently ignored. In slow environments this causes avoidable aborts and skipped context injection even when operators explicitly raise the timeout, making plugin behavior inconsistent with its config contract.

Useful? React with 👍 / 👎.

Comment on lines +129 to +130
child.stderr.on("data", (chunk: Buffer) => {
stderr += chunk.toString("utf8");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Bound stderr buffering in brv process runner

Only stdout is size-limited, but stderr is appended without any cap, so a noisy or failing brv invocation can still accumulate unbounded output in memory and defeat the intended output-safety guard. This can lead to unnecessary memory pressure/OOM during error scenarios, especially since this path runs on every turn for curation/query.

Useful? React with 👍 / 👎.

@greptile-apps

greptile-apps Bot commented Mar 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR introduces the ByteRover context engine plugin (extensions/byterover/) — a new opt-in extension that persists curated conversation knowledge beyond OpenClaw's compaction window by delegating to the brv local CLI. The core change is minimal (optional prompt? parameter on assemble(), threaded through attempt.ts) and backward-compatible; all existing engines are unaffected. The plugin itself is well-structured: a settled-guard in runBrv prevents race conditions, SIGKILL propagation via AbortSignal ensures clean child-process teardown, the POSIX -- terminator blocks flag injection, metadata stripping prevents OpenClaw-internal markup from leaking into brv, and the systemPromptAddition injection strategy correctly avoids context feedback loops.

Two issues worth addressing before merge:

  • Unbounded stderr buffer in runBrv (brv-process.ts:129–131): stdout is correctly capped at 512 KB, but stderr has no size limit. A verbose or misbehaving brv process can cause unlimited heap growth — the exact scenario maxOutputChars was introduced to prevent. Stderr should be truncated at the same limit.
  • queryTimeoutMs silently capped at 10 s during assembly (context-engine.ts:145–147): assemble() applies Math.min(queryTimeoutMs, 10_000) as the AbortController deadline, overriding any user-configured value above 10 s without warning or documentation. The openclaw.plugin.json schema describes queryTimeoutMs as a general query timeout, so users who set larger values (e.g., for slow daemons) will not get the behaviour they expect.

Confidence Score: 4/5

  • Safe to merge with minor fixes — the plugin is well-isolated and opt-in, with no impact on existing engines or compaction logic.
  • The PR is a clean, opt-in extension with solid process-lifecycle management, thorough tests (54 passing), and zero modifications to existing compaction or message-format contracts. The two issues found (unbounded stderr buffer and silent queryTimeoutMs cap) are both in the new plugin code only, and neither causes data loss or agent failure — errors are caught and the agent proceeds without context. The unbounded stderr is the more pressing concern from a memory-safety standpoint, but the practical risk is low for a local CLI tool under normal conditions.
  • extensions/byterover/brv-process.ts (stderr cap), extensions/byterover/context-engine.ts (queryTimeoutMs documentation/cap)
Prompt To Fix All With AI
This is a comment left during a code review.
Path: extensions/byterover/brv-process.ts
Line: 129-131

Comment:
**Unbounded `stderr` accumulation**

`stdout` is correctly capped at `maxOutput` (512 KB by default), but `stderr` has no size limit. A misbehaving or unexpectedly verbose `brv` process (e.g., verbose logging mode, crash dump, or a corrupted install) can grow `stderr` without bound in the gateway process's heap, creating the same memory-exhaustion vector that `maxOutput` was introduced to prevent.

```suggestion
    child.stderr.on("data", (chunk: Buffer) => {
      stderr += chunk.toString("utf8");
      if (stderr.length > maxOutput) {
        stderr = stderr.slice(0, maxOutput) + "\n[stderr truncated]";
      }
    });
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/byterover/context-engine.ts
Line: 145-147

Comment:
**`queryTimeoutMs` silently capped at 10 s for assembly**

The `assembleTimeout` is `Math.min(queryTimeoutMs, 10_000)`, so a user who sets `queryTimeoutMs: 20000` in their config will observe a hard 10 s ceiling with no warning. Meanwhile `runBrv` receives the full configured value as its internal timer — meaning the AbortController always wins first, making the configured value effectively useless above 10 000 ms.

The `openclaw.plugin.json` schema describes `queryTimeoutMs` as "Timeout in milliseconds for brv query calls" with no mention of this cap, so users will reasonably expect their setting to be honoured.

Two options:

1. **Document the cap in the schema description** (minimal change):
```json
"queryTimeoutMs": {
  "type": "number",
  "description": "Timeout for brv query calls (ms). Defaults to 12000. Note: effective assemble deadline is capped at 10000 ms to stay within the agent ready timeout."
}
```

2. **Expose the cap as a separate config field** (`assembleQueryTimeoutMs`) so the two knobs are independent and both user-controlled.

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: ba829ff

Comment thread extensions/byterover/brv-process.ts
Comment thread extensions/byterover/context-engine.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b57679057c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +186 to +190
const AGENT_TAG_RE = /<\s*\/?\s*(?:final|think)\s*>/gi;

export function stripAssistantTags(text: string): string {
if (!text) return text;
return text.replace(AGENT_TAG_RE, "");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Strip block contents before curation

stripAssistantTags removes only the <think>/<final> delimiters, so assistant messages like <think>internal reasoning</think><final>answer</final> are transformed into internal reasoninganswer and the hidden reasoning is sent to brv curate. This means non-final chain-of-thought text can be persisted and later re-injected via systemPromptAddition, which contaminates retrieved context and can surface speculative/unsafe internal reasoning in future turns.

Useful? React with 👍 / 👎.

@ncnthien

Copy link
Copy Markdown

can't wait for this

@DatPham-6996

Copy link
Copy Markdown

This PR significantly improves how the agent manages context, let's get this merged.

@danhdoan

Copy link
Copy Markdown
Contributor Author

Which plan do I need for this to work? https://www.byterover.dev/pricing

Thanks for your interest, @asyncjason!

ByteRover is now supporting 4 plans as below:
Free: You can still use curate/query, but it is limited to 50 requests per day or 200 requests per month. BYOK is also supported. Push/pull remote context is not included.
Pro: Best for a single user. It includes Cloud Sync, so you can push and pull context remotely.
Team: Best for multiple users who need the same remote sync capability, plus more storage and collaboration-oriented features.
Enterprise: Best for organizations that need advanced security, custom deployment, or enterprise-scale control.
If you have any questions or want help choosing the best plan, feel free to reach out on our
Discord: https://discord.gg/nTVhC6EX

In short: I suggest you first try Pro plan to explore and experience full functionalities. You would love it!

Add optional `prompt` field to the ContextEngine `assemble` interface so
context engines can prepare relevant context based on the current user
message rather than only historical messages.
Integrates the brv CLI as an OpenClaw context engine that curates
conversation turns and queries curated knowledge for prompt injection.

- assemble: queries brv for relevant context, injects as
  systemPromptAddition
- afterTurn: feeds new turn messages to brv curate (fire-and-forget)
- compact: delegates to runtime (brv daemon manages its own compaction)
- Uses api.logger throughout, ENOENT gives actionable install guidance
- Arg terminator (--) prevents user text from being parsed as brv flags
scoped plugin-sdk subpath

- afterTurn: prepend curation instructions that tell brv to skip trivial
  messages (greetings, acks, session-start commands) server-side
- assemble: skip brv query when stripped query is < 5 chars (avoids
  spawning for "ok", "hi", "yes" — applied after metadata stripping)
- Migrate imports from monolithic openclaw/plugin-sdk to scoped
  openclaw/plugin-sdk/byterover subpath (new
  src/plugin-sdk/byterover.ts)
- Wire export map entry in package.json and register in subpaths test
… integration tests

- Add settled guard in runBrv to prevent double resolve/reject from
  competing event handlers (timer, signal, overflow, error, close)
- Replace Promise.race timeout in assemble with AbortController signal
  passed through brvQuery → runBrv for clean child-process cancellation
- Expand detach comment to clarify brv daemon handshake behavior
- Remove dead code: brvStatus function and BrvStatusResult type
- Add 12 integration tests covering afterTurn→brvCurate, assemble→brvQuery,
  full lifecycle, abort handling, and error fallback paths
…t ceiling

- Truncate stderr at maxOutput (512KB) to prevent unbounded memory growth
  from verbose or crashing brv processes
- Document the 10s assemble deadline cap in queryTimeoutMs schema description
  so users understand why values above 10000 ms are not honored
- Add "byterover" to pluginSdkSubpaths in vitest.config.ts so the
  openclaw/plugin-sdk/byterover import resolves without dist/ on CI
- Use typeof import() for vi.fn generics to properly type mock params
@openclaw-barnacle openclaw-barnacle Bot added the scripts Repository scripts label Mar 16, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 78e0d8a191

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

const maxOutput = params.maxOutputChars ?? 512_000;

params.logger.debug?.(
`spawn: ${params.brvPath} ${params.args.join(" ")} (cwd=${params.cwd}, timeout=${params.timeoutMs}ms)`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Redact conversation text from spawn debug logs

runBrv currently logs params.args.join(" "), which includes raw user query text and full serialized conversation payloads for brv curate; when debug logging is enabled, this writes sensitive conversation content (and potentially very large blobs) into logs on every turn. That creates avoidable data-leak and log-growth risk in real deployments, so this log line should avoid printing user-supplied args verbatim (for example, log subcommand plus payload length only).

Useful? React with 👍 / 👎.

}
}
// "--" terminates flags so user text starting with "-" isn't parsed as a brv option
args.push("--", params.context);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Badge Send curate payload via stdin instead of argv

brvCurate passes the entire serialized turn as a positional CLI argument, so curation is constrained by OS command-line limits (ARG_MAX); long code snippets or verbose assistant replies can trigger spawn E2BIG and skip curation for exactly the large-context cases this plugin targets. Because afterTurn treats failures as best-effort, this becomes a silent memory-loss path rather than a hard failure, so the payload should be streamed via stdin (or another non-argv transport).

Useful? React with 👍 / 👎.

@JaySon-Huang

Copy link
Copy Markdown

Nice direction overall — the afterTurn -> brv curate / assemble -> brv query split makes sense, and passing prompt into assemble() feels like a clean way to support retrieval-oriented context engines.

I do think the compact() part needs another look.

Right now byterover sets ownsCompaction: false, but compact() is effectively a no-op and just returns { ok: true, compacted: false }.

The key issue is that, in the current OpenClaw runtime, ownsCompaction: false does not mean “fall back to legacy compaction.” It only means this engine does not own the compaction lifecycle. The active engine’s compact() is still called directly for both manual /compact and overflow recovery.

So when byterover is the active context engine, compaction is effectively disabled:

  • manual /compact degrades into Compaction skipped
  • overflow recovery loses the normal compaction path
  • the returned reason says “delegating to runtime,” but no actual delegation happens

For comparison, the built-in LegacyContextEngine is also non-owning, but its compact() still bridges to the built-in compaction runtime and forwards the runtime context. That seems like the important distinction here: non-owning is fine, but non-owning + no-op compact() is not.

I think this should be fixed in one of two ways:

  1. keep ownsCompaction: false, but make compact() actually delegate to the built-in OpenClaw compaction runtime; or
  2. if ByteRover wants to own this behavior, switch to ownsCompaction: true and implement real compaction semantics.

Given the rest of the PR, option 1 seems more consistent with the current design boundary: ByteRover handles long-term memory curation/retrieval, while OpenClaw continues to own short-term session compaction.

Without that change, this PR seems to unintentionally disable compaction whenever byterover is configured as the active context engine.

@jalehman

Copy link
Copy Markdown
Contributor

Thanks for this @danhdoan, and for the insightful review and ensuing conversation about ownsCompaction @JaySon-Huang. I am looking into the comments on the docs thread about ownsCompaction behavior and will keep you updated on that.

As for this PR, we're not accepting new plugins into this repository. It's bad for you because you need to wait for our review any time you want to update your plugin; it's bad for us because it adds large amounts of new code surface area that we shouldn't be responsible for maintaining.

The better pattern is to create your own repository to host the plugin and publish it to NPM yourself. Then you can own the full maintenance lifecycle. Things are in the works to boost plugin visibility via a big update to clawhub that should land pretty soon. As a reference, check out lossless-claw, which is a context engine plugin that's hosted in an external repository. It's been very helpful for me to be able to maintain that independently of this project.

@danhdoan

danhdoan commented Mar 18, 2026

Copy link
Copy Markdown
Contributor Author

Hi @jalehman, thanks for clarifying this. I agree with this decision and I will develop an external plugin as the next step.

However, there is 1 more thing I should ask for your opinion first. Currently assemble interface only provides history message, and does not include the new message from user. From my point of view, the new message is also helpful as it could be used to collect relevant memories/contexts and add to the prompt.
I suggest we could add optional argument prompt?: string to the assemble() interface. This change is minimal, only add a few changes in the core, and is totally compatible with current design. This only supports my plugin to work well with ByteRover.

Happy to adjust my approach based on your feedback.

@danhdoan

Copy link
Copy Markdown
Contributor Author

Hi @jalehman, thanks for the feedback on the original PR,

I've split out the upstream interface change into its own PR: #50848. It adds the optional prompt param to ContextEngine.assemble() so retrieval-oriented engines can use the user's query at assembly time. Small change - 3 files, no behavioral change for existing engines.

Let me know if anything needs adjusting!

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

Labels

agents Agent runtime and tooling scripts Repository scripts size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants