Skip to content

fix: enable the OpenHands SDK default condenser - #383

Open
mnajafian-nv wants to merge 7 commits into
NVIDIA:mainfrom
mnajafian-nv:fix/openhands-default-condenser
Open

mnajafian-nv wants to merge 7 commits into
NVIDIA:mainfrom
mnajafian-nv:fix/openhands-default-condenser

Conversation

@mnajafian-nv

@mnajafian-nv mnajafian-nv commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Overview

Enable the OpenHands SDK default condenser. Without it, long runs resend their full history and can fail at the model context limit. Runs now summarize older events by default; harness.settings.condenser: none keeps the previous behavior. Summarization adds to reported model usage and consumes a max_turns iteration. No dependency change.

Details

  • Configure the condenser with the agent LLM and validate the default/none setting; regenerate the adapter catalog.
  • Document the trigger, opt-out, usage, and turn-limit behavior.
  • Test event-limit and context-error condensation with OpenHands SDK 1.50.0 and a stubbed model transport. A focused CI step runs both cases.

Validation

  • Focused OpenHands and settings tests: 84 passed with SDK 1.50.0.
  • Full Python suite before the final test and CI commits: 1,934 passed, 93 skipped; Rust workspace: 161 passed.
  • Formatting, actionlint, and pre-commit passed. The dependency license diff hook was skipped on the final all-files run because no dependency files changed; it timed out when run separately.
  • No credentialed model run; the new tests use a stubbed transport.

Where should the reviewer start?

Review start() and _condenser_enabled() in adapters/python/openhands/src/nemo_fabric_adapters/openhands/adapter.py, then the two SDK-backed cases in tests/adapters/test_openhands.py.

Related Issues: (use one of the action keywords Closes / Fixes / Resolves / Relates to)

  • Relates to: none

  • I confirm this contribution is my own work, or I have the right to submit it under this project's license.

  • I searched existing issues and open pull requests, and this does not duplicate existing work.

Summary by CodeRabbit

  • New Features
    • OpenHands now summarizes older conversation history by default, helping interactions continue when history grows large or exceeds the model’s context window.
    • Set condenser to none to preserve the full conversation history. Supported values are default and none.
    • Summarization calls count toward usage, and each history-condensation step counts toward the maximum turn limit.
  • Documentation
    • Updated OpenHands integration guidance with condenser behavior and configuration details.

The OpenHands SDK leaves Agent.condenser unset, and the adapter built
its agent without one. Long runs therefore resent the full event
history on every model request, and a context-window error from the
model failed the invocation instead of triggering condensation.

Configure the SDK default_condenser, the LLMSummarizingCondenser sizing
(80 events, keep the first 4) that the OpenHands default agent uses.
Pass the agent LLM object itself rather than a copy with a separate
usage ID, so summarization calls accrue to the metrics the adapter
reports as invocation usage.

This changes default runtime behavior for OpenHands runs. The adapter
descriptor declares no settings, so the condenser is not configurable.

Signed-off-by: mnajafian-nv <mnajafian@nvidia.com>
The OpenHands adapter now summarizes older conversation history.
Document when condensation triggers, that summarization calls count
toward invocation usage, and that NeMo Fabric does not expose settings
to disable or tune it.

Signed-off-by: mnajafian-nv <mnajafian@nvidia.com>
Condensing history by default adds summarization model calls and can
change results for an unchanged configuration. Give users who need the
previous behavior, for example to compare against earlier runs, an
explicit opt-out through the adapter's existing settings schema rather
than a new configuration surface.

harness.settings.condenser accepts default, the OpenHands SDK default
condenser, or none, which builds the agent without a condenser as
before. Planning rejects any other value. Planning does not apply
schema defaults, so the adapter treats a missing value as default.

Regenerate the adapter catalog for the descriptor change and document
the setting in the adapter README, the integration guide, and the
adapter configuration matrix.

Signed-off-by: mnajafian-nv <mnajafian@nvidia.com>
The adapter enabled the condenser for every condenser value other than
"none". Planning rejects other values, but a host that starts the
adapter without planning could pass "off" or "None" and silently get
summarization calls, which cost model usage.

Accept only "default" and "none" in the adapter and raise
openhands_condenser_invalid for anything else, matching how an existing
adapter re-validates its enum settings. Add a test for unknown string
and null values.

Signed-off-by: mnajafian-nv <mnajafian@nvidia.com>
Each condensation returns from an OpenHands agent step, and the SDK
counts every step toward max_iteration_per_run, which the adapter sets
from runtime.max_turns. A run with a tight max_turns that used to
finish can now stop at the iteration limit, so say so.

Also state that the trigger is the history sent to the model rather
than the total event count, replace the sentence that contradicted the
condenser setting with "does not expose condenser tuning parameters",
mention that other setting values are rejected, and wrap the new
paragraphs like the surrounding text.

Signed-off-by: mnajafian-nv <mnajafian@nvidia.com>
The condenser tests only checked how start() builds the agent, so
nothing showed that a run condenses its history, keeps going, and
reports the summarization call in invocation usage.

Drive the adapter with OpenHands SDK 1.50.0 and a stubbed LiteLLM
transport: once past the 80-event limit, and once after a context
window error. Each case asserts one Condensation event, a successful
finish, and usage that includes the summarization call. The test skips
when the OpenHands SDK is not installed.

Signed-off-by: mnajafian-nv <mnajafian@nvidia.com>
Signed-off-by: mnajafian-nv <mnajafian@nvidia.com>
@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository: NVIDIA/NeMo-Fabric/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Enterprise
  • Run ID: bfdc9ba0-b6ef-4565-9589-97f5f8dcd22e



📥 Commits

Reviewing files that changed from the base of the PR and between a17f316 and da552dc.




📒 Files selected for processing (9)
  • .github/workflows/ci_python.yml
  • adapters/README.md
  • adapters/python/openhands/README.md
  • adapters/python/openhands/openhands.fabric-adapter.json
  • adapters/python/openhands/src/nemo_fabric_adapters/openhands/adapter.py
  • docs/integrations/harness/openhands.mdx
  • sdk/python/nemo-fabric-adapter-catalog/src/nemo_fabric_adapter_catalog/catalog.json
  • tests/adapters/test_openhands.py
  • tests/python/test_harness_settings_validation.py



Included review availability: This review used your included allowance. Your plan provides up to 12 included reviews per hour; 10 remain after this review.




📜 Recent review details
⏰ Context from checks skipped due to timeout. (28)
  • GitHub Check: Preview docs
  • GitHub Check: Test (Python 3.12, linux-arm64)
  • GitHub Check: Test (Python 3.13, linux-amd64)
  • GitHub Check: Test (Python 3.14, macos-arm64)
  • GitHub Check: Test (Python 3.13, windows-amd64)
  • GitHub Check: Test (Python 3.12, windows-amd64)
  • GitHub Check: Test (Python 3.11, linux-amd64)
  • GitHub Check: Test (Python 3.11, macos-arm64)
  • GitHub Check: Test (Python 3.13, linux-arm64)
  • GitHub Check: Test (Python 3.11, linux-arm64)
  • GitHub Check: Test (Python 3.11, windows-amd64)
  • GitHub Check: Test (Python 3.12, linux-amd64)
  • GitHub Check: Test (Python 3.12, macos-arm64)
  • GitHub Check: Test (Python 3.13, macos-arm64)
  • GitHub Check: Test (Python 3.14, linux-arm64)
  • GitHub Check: Test (Python 3.14, windows-amd64)
  • GitHub Check: Test (Python 3.14, linux-amd64)
  • GitHub Check: OpenCode E2E
  • GitHub Check: Cline E2E
  • GitHub Check: Test (Node 24)
  • GitHub Check: Hermes adapter (upstream Relay 0.9, Python 3.14)
  • GitHub Check: Test (arm64)
  • GitHub Check: Qwen Code E2E
  • GitHub Check: Test adapters (Node 22.19.0)
  • GitHub Check: Test adapters (Node 24)
  • GitHub Check: Test (x86_64)
  • GitHub Check: Test (Node 20.18.3)
  • GitHub Check: Pre-commit



🧰 Additional context used
📚 Code guidelines (6)
.agents/skills/maintain-packaging/SKILL.md — configured
.agents/skills/maintain-ci/SKILL.md — configured
.agents/skills/contribute-adapter/SKILL.md — configured
adapters/README.md — auto-discovered
.agents/skills/contribute-docs/SKILL.md — configured
.agents/skills/review-doc-style/SKILL.md — configured

📓 Path-based instructions (13)
Review documentation for technical accuracy against the current API, command correctness, and consistency with generated schemas.

⚙️ CodeRabbit configuration file

Files:

  • docs/integrations/harness/openhands.mdx

Enforce the product name in user-facing prose: use "NVIDIA NeMo Fabric" on first use and "NeMo Fabric" thereafter.

⚙️ CodeRabbit configuration file

Files:

  • adapters/README.md
  • adapters/python/openhands/README.md
  • docs/integrations/harness/openhands.mdx

Review adapter and example changes for command correctness, config/schema consistency, artifact handling, and compatibility with the public NeMo Fabric contracts.

⚙️ CodeRabbit configuration file

Files:

  • adapters/README.md
  • adapters/python/openhands/openhands.fabric-adapter.json
  • adapters/python/openhands/README.md
  • adapters/python/openhands/src/nemo_fabric_adapters/openhands/adapter.py

Tests should cover the behavior promised by the changed API surface, including error paths, lifecycle cleanup, and SDK/native parity where relevant.

⚙️ CodeRabbit configuration file

Files:

  • tests/python/test_harness_settings_validation.py
  • tests/adapters/test_openhands.py

Source excerpt: Metadata-only adapter catalog under `sdk/python/nemo-fabric-adapter-catalog`: regenerate its single resource bundle with `just adapter-catalog` and check freshness with `just check-adapter-catalog`.

📄 CodeRabbit inference engine (.agents/skills/maintain-packaging/SKILL.md)

Files:

  • sdk/python/nemo-fabric-adapter-catalog/src/nemo_fabric_adapter_catalog/catalog.json

Source excerpt: Use this skill when a change touches `.github/workflows/*.yml` or `.github/workflows/*.yaml`, or when reviewing CI behavior for security, reliability, or reproducibility.

📄 CodeRabbit inference engine (.agents/skills/maintain-ci/SKILL.md)

Files:

  • .github/workflows/ci_python.yml

Source excerpt: Follow these repository-specific requirements after applying the public skill: Place a Python adapter under `adapters/python//` with `LICENSE -> ../../../LICENSE`, `README.md`, `.fabric-adapter.json`, Python pack...

📄 CodeRabbit inference engine (.agents/skills/contribute-adapter/SKILL.md)

Files:

  • adapters/python/openhands/openhands.fabric-adapter.json
  • adapters/python/openhands/README.md
  • adapters/python/openhands/src/nemo_fabric_adapters/openhands/adapter.py

Source excerpt: The adapter descriptor selected in `RunPlan` is authoritative for normalized configuration, its adapter-owned settings schema, and telemetry support.

📄 CodeRabbit inference engine (adapters/README.md)

Files:

  • adapters/README.md

Source excerpt: In MDX files, top-of-file comments must use JSX comment delimiters: `{/*` to open and `*/}` to close.

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

Files:

  • docs/integrations/harness/openhands.mdx

Source excerpt: MDX top-of-file SPDX comments use HTML comment delimiters instead of `{/* ...

📄 CodeRabbit inference engine (.agents/skills/review-doc-style/SKILL.md)

Files:

  • docs/integrations/harness/openhands.mdx

Source excerpt: For links between files under `docs/`, use paths relative to the source file and include the target file's `.mdx` extension.

📄 CodeRabbit inference engine (.agents/skills/review-doc-style/SKILL.md)

Files:

  • docs/integrations/harness/openhands.mdx

Source excerpt: [ ] Relevant adapter or example `README.md` files updated when examples or adapters have changed.

📄 CodeRabbit inference engine (.agents/skills/contribute-docs/SKILL.md)

Files:

  • adapters/README.md

Source excerpt: Follow these repository-specific requirements after applying the public skill: Give each Python leaf adapter a small base installation, a `harness` extra for package-installable target packages, and a `full` extra for packag...

📄 CodeRabbit inference engine (.agents/skills/contribute-adapter/SKILL.md)

Files:

  • adapters/python/openhands/openhands.fabric-adapter.json
  • adapters/python/openhands/README.md
  • adapters/python/openhands/src/nemo_fabric_adapters/openhands/adapter.py

🪛 ast-grep (0.45.3)
tests/adapters/test_openhands.py

[info] 395-395: use jsonify instead of json.dumps for JSON output
Context: json.dumps(arguments)
Note: [CWE-116] Improper Encoding or Escaping of Output.

(use-jsonify)


🪛 zizmor (1.30.1)
.github/workflows/ci_python.yml

[warning] 4-382: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block

(excessive-permissions)







🔇 Additional comments (13)
adapters/README.md (2)

100-100: 📐 Maintainability & Code Quality | 💤 Low value

Fix the duplicate and inconsistent Kilo Code row.

The table has two "Kilo Code" rows (Lines 99 and 100). Line 99 describes a session-lifecycle model ("Reuses the session...", "Deletes the session...", "Adapter-owned loopback service") under the Models, MCP, Skills, and Subagents columns. These values do not match the column meanings. The Line 100 row contains the correct configuration values. Line 99 is not part of this change, but the changed harness.settings row at Line 135 sits in the same table set. Remove or correct Line 99 if this PR touches it. Otherwise, track it separately.


135-135: LGTM!


.github/workflows/ci_python.yml (1)

62-63: Job-level permissions are already minimal; the zizmor warning is a false positive for this job.

The test job sets permissions: contents: read. The warning refers to the missing workflow-level block. The repository guidance prefers job-level permissions. No change is needed.


adapters/python/openhands/openhands.fabric-adapter.json (1)

31-38: LGTM!


sdk/python/nemo-fabric-adapter-catalog/src/nemo_fabric_adapter_catalog/catalog.json (1)

1667-1677: LGTM!

Also applies to: 1686-1686


adapters/python/openhands/src/nemo_fabric_adapters/openhands/adapter.py (3)

143-147: Fail-fast validation is correct.

The code rejects unknown values, including None, instead of falling back silently. This matches the fail-fast configuration rule. One edge case: condenser not in ("default", "none") raises TypeError for an unhashable value only with sets or dicts. A tuple uses ==, so a list or dict value is safe. No change is needed.


366-369: LGTM!


141-142: 🩺 Stability & Availability

The contract rejects non-mapping settings values before the adapter uses them. Omitted settings receives an empty dictionary, and None or another non-mapping value raises ContractValidationError.


tests/adapters/test_openhands.py (2)

299-346: LGTM!


205-216: LGTM!


tests/python/test_harness_settings_validation.py (1)

163-167: LGTM!

Also applies to: 497-502


adapters/python/openhands/README.md (1)

77-99: LGTM!


docs/integrations/harness/openhands.mdx (1)

71-94: LGTM!






Walkthrough

The OpenHands adapter now supports an enabled-by-default history condenser. The condenser setting accepts default or none. Tests cover setting validation, startup configuration, and condensation during invocation.

Changes

OpenHands condenser

Layer / File(s) Summary
Condenser setting contract
adapters/README.md, adapters/python/openhands/openhands.fabric-adapter.json, sdk/python/nemo-fabric-adapter-catalog/src/nemo_fabric_adapter_catalog/catalog.json, adapters/python/openhands/src/nemo_fabric_adapters/openhands/adapter.py, tests/adapters/test_openhands.py, tests/python/test_harness_settings_validation.py, adapters/python/openhands/README.md, docs/integrations/harness/openhands.mdx
The schemas allow condenser values default and none, with default as the default. The adapter rejects other values. Documentation describes the condenser behavior and how to disable it.
Condenser startup and invocation
adapters/python/openhands/src/nemo_fabric_adapters/openhands/adapter.py, tests/adapters/test_openhands.py, .github/workflows/ci_python.yml
The adapter loads the SDK default condenser and attaches it to the agent when enabled, using the agent LLM. Tests cover startup settings and condensation during invocation. CI runs the targeted condensation test.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Sequence Diagram(s)

sequenceDiagram
  participant HarnessConfig
  participant OpenHandsAdapter
  participant OpenHandsAgent
  participant AgentLLM
  OpenHandsAdapter->>HarnessConfig: Read condenser setting
  OpenHandsAdapter->>OpenHandsAdapter: Create default_condenser with agent LLM when enabled
  OpenHandsAdapter->>OpenHandsAgent: Attach condenser during startup
  OpenHandsAgent->>AgentLLM: Summarize history during condensation
Loading

Merge Risk: ⚪ Minimal · up to da552

The condenser change is mergeable after normal checks; no actionable merge-blocking issue remains.

Pre-merge checks | Passed 4 | Failed 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 15 functions across 3 files. (6 skipped: 6… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Title check Passed The title follows Conventional Commits format with the allowed lowercase type "fix", uses an imperative summary, stays under 72 characters, has no trailing period, and accurately describes the change.
Description check Passed The description includes the required overview, reviewer starting point, related-issues section with an allowed action keyword, and both contribution confirmation checkboxes. It also provides implemen…

Full details: Docstring Coverage

Explanation

Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 15 functions across 3 files. (6 skipped: 6 unsupported.)


  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR





  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

@mnajafian-nv
mnajafian-nv marked this pull request as ready for review October 10, 2026 17:32
@mnajafian-nv
mnajafian-nv requested review from a team as code owners October 10, 2026 17:32
@mnajafian-nv mnajafian-nv self-assigned this Oct 10, 2026

This branch was successfully deployed

1 active deployment
fern — da552dce Deployed Oct 10, 2026 by copy-pr-bot[bot] via Preview docs #1986
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant