Skip to content

fix(hermes): register bare tool schemas so strict providers accept them - #7068

Merged
apurvvkumaria merged 2 commits into
mainfrom
fix/7067-hermes-plugin-tool-schema-unwrap
Jul 17, 2026
Merged

fix(hermes): register bare tool schemas so strict providers accept them#7068
apurvvkumaria merged 2 commits into
mainfrom
fix/7067-hermes-plugin-tool-schema-unwrap

Conversation

@jason-ma-nv

@jason-ma-nv jason-ma-nv commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

The NemoClaw Hermes plugin registered its four tools by passing a pre-wrapped OpenAI envelope ({"type":"function","function":{...}}) to ctx.register_tool. Hermes wraps registered schemas again at request-build time, so the outbound tools[] entries were double-wrapped. Lenient endpoints tolerate the extra nesting, but Google Gemini's strict OpenAI-compatible endpoint rejects the whole request with HTTP 400 (Unknown name "function" at 'tools[i].function'), breaking every conversation for Gemini sandboxes; transcribe_audio additionally lost its real parameters (dropped to {} at the outer level). After this change the plugin passes the bare function object, so Hermes adds exactly one envelope and the tools validate on strict providers.

Related Issue

Closes #7067

Changes

  • agents/hermes/plugin/__init__.py: unwrap the schema= argument for all four register_tool calls (nemoclaw_status, nemoclaw_info, transcribe_audio, nemoclaw_reload_skills) — pass {"name", "description", "parameters"} directly instead of a pre-wrapped {"type":"function","function":{...}} envelope. This is the fix at the layer that produced the malformed shape (our plugin), rather than adding defensive normalization downstream in Hermes. The file is copied verbatim into the image (agents/hermes/Dockerfile), so the source edit fully covers the deployed /sandbox/.hermes/plugins/nemoclaw/__init__.py.
  • agents/hermes/plugin/test_register_tools.py (new): registers the tools against a fake ctx and asserts each schema is a bare function object (top-level name/parameters, no nested envelope) and that transcribe_audio keeps its real parameters. There is no existing Python test harness for this plugin, so this is a standalone unittest (stdlib + PyYAML, no Hermes runtime).
  • Out of scope (noted for maintainers): agents/hermes/plugin/plugin.yaml's provides_tools omits transcribe_audio — a manifest inconsistency, not a cause of the 400; left unchanged to keep this fix minimal.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification: internal Hermes plugin tool-schema shape; no user-facing surface, flag, or documented behavior changes.
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: Approved by on the current head: fix(hermes): register bare tool schemas so strict providers accept them #7068 (review)
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Verification

  • PR description includes a Signed-off-by: line and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run check:diff passed when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result: python3 -m unittest test_register_tools (in agents/hermes/plugin/) → 3 passed; confirmed red on the pre-fix double-wrap (4 failures + 1 error, incl. transcribe_audio params dropped) and green after. Note: CI has no Python lane for agents/, so this test is host-verified (run locally and on a clean host checkout), not executed by CI.
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result:
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Verification detail

  • Proven: unit-level shape contract — the four tools register as single-wrapped bare function objects and transcribe_audio retains file_path/model/required. Red/green confirmed by reverting only the source fix. Run locally and on a clean host checkout (Node/Python 22).
  • Remains (blocked E2E): full end-to-end nemohermes onboard with the Google Gemini provider and a live message, which needs a Gemini-provider credential/sandbox not available to this loop. A maintainer/reporter can confirm with the issue's repro (onboard Gemini → send a message → expect no HTTP 400; inspect model_tools.get_tool_definitions() for single-wrapped entries).

Signed-off-by: Jason Ma jama@nvidia.com

Summary by CodeRabbit

  • Bug Fixes

    • Improved tool registration compatibility with strict AI providers by using the expected schema format.
    • Updated tool descriptions for clearer status, information, audio transcription, and skill-reload guidance.
  • Tests

    • Added coverage verifying registered tools, schema structure, and required audio transcription parameters.

The NemoClaw Hermes plugin registered its four tools (nemoclaw_status,
nemoclaw_info, nemoclaw_reload_skills, transcribe_audio) by passing a
pre-wrapped OpenAI envelope (`{"type":"function","function":{...}}`) to
`ctx.register_tool`. Hermes wraps registered schemas again at request-build
time, so the outbound `tools[]` entries became double-wrapped
(`{"type":"function","function":{"type":"function","function":{...}}}`).
Lenient endpoints (NVIDIA build, Azure) tolerate the nesting, but Google
Gemini's strict OpenAI-compatible endpoint rejects the whole request with
HTTP 400 (`Unknown name "function" at tools[i].function`), breaking every
conversation. For transcribe_audio the double-wrap also dropped its real
`parameters` (file_path/model) to `{}` at the outer level.

Pass the bare function object to `register_tool` so Hermes adds exactly one
envelope, producing spec-valid single-wrapped tools and preserving
transcribe_audio's parameters.

Adds a standalone unittest that registers the tools against a fake ctx and
asserts each schema is a bare function object (no nested envelope) and that
transcribe_audio keeps its real parameters.

Closes #7067

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Jason Ma <jama@nvidia.com>
@jason-ma-nv jason-ma-nv self-assigned this Jul 17, 2026
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The Hermes NemoClaw plugin now registers four tools using bare function schemas instead of pre-wrapped envelopes. Tool descriptions were updated, the transcription parameters were made explicit, and standalone tests validate registration names and schema structure.

Changes

Hermes tool schema registration

Layer / File(s) Summary
Bare tool schema registration
agents/hermes/plugin/__init__.py
The four NemoClaw tools now pass unwrapped name, description, and parameters schemas; transcribe_audio defines file_path and optional model parameters.
Schema shape regression tests
agents/hermes/plugin/test_register_tools.py
Standalone tests verify the registered tool set, reject nested function envelopes, and confirm the required transcription parameter remains present.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The plugin now passes unwrapped function schemas and preserves transcribe_audio parameters, matching issue #7067.
Out of Scope Changes check ✅ Passed The added test module and description/comment updates support the schema fix and do not introduce unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: registering bare tool schemas to satisfy strict providers.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/7067-hermes-plugin-tool-schema-unwrap

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

@github-code-quality

github-code-quality Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage remains at 96%, unchanged from the main branch.

TypeScript / code-coverage/cli

The overall coverage in the fix/7067-hermes-plug... branch remains at 80%, unchanged from the main branch.

Show a code coverage summary of the most impacted files.
File main e7e8b67 fix/7067-hermes-plug... e6bef9c +/-
src/lib/inferen...lama/process.ts 100% 50% -50%
src/lib/core/pr...mpt-activity.ts 92% 67% -25%
src/lib/sandbox...vileged-exec.ts 87% 75% -12%
src/lib/inferen...er-lifecycle.ts 71% 65% -6%
src/lib/credentials/store.ts 64% 59% -5%
src/lib/adapter...hell/resolve.ts 100% 100% 0%
src/lib/agent/defs.ts 81% 81% 0%
src/lib/agent/s...store-reader.ts 90% 90% 0%
src/lib/state/registry.ts 83% 86% +3%
src/lib/domain/.../connect-env.ts 89% 97% +8%

Updated July 17, 2026 20:44 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

github-actions Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Informational

Advisor assessment: Informational / medium confidence
Next action: Review the warnings below.
Findings: 0 blockers · 1 warning · 0 suggestions
Status: Canonical ledger: 0 blocker(s), 1 warning(s), 0 suggestion(s).

Model lanes

  • GPT-5.6 Terra (primary): Completed · medium confidence · 0 blockers · 1 warning · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions
  • Model comparison: normalized findings differ; normalized E2E selections differ; Nemotron reported the same number of blockers, 1 fewer warning, the same number of suggestions.

Nemotron output stays in workflow artifacts and does not change the assessment above.

E2E guidance

Advisory only. E2E / PR Gate selects and runs jobs independently.

Recommended E2E: full-e2e, hermes-e2e, security-posture

1 warning · 0 suggestions

Warnings

Warnings do not block.

PRA-1 Warning — Test the schema after Hermes applies its request envelope

  • Location: agents/hermes/plugin/test_register_tools.py:61
  • Category: tests
  • Problem: The added test captures only the bare schema passed to a fake `register_tool`. The reported defect occurs later, when the actual Hermes runtime converts registrations into provider tool definitions, so the test would still pass if that integration applied no envelope, retained a double envelope, or moved `transcribe_audio` parameters to the wrong level.
  • Impact: A future change to the real Hermes registration/request-builder contract can reintroduce Gemini-rejecting double-wrapped tools while the mocked unit test remains green, preventing every conversation for strict-provider sandboxes.
  • Recommendation: Add a focused Hermes-runtime integration regression test that registers this plugin and inspects the generated provider tool definitions: each of the four tools must have exactly one `{"type":"function","function":...}` envelope, and `transcribe_audio.function.parameters` must retain `file_path`, `model`, and its required field.
  • Verification: Inspect a test using the real Hermes request-builder or `model_tools.get_tool_definitions()` after plugin registration; confirm it asserts exactly one envelope for all four registered tools.
  • Test coverage: A Hermes-runtime integration test that registers the plugin, obtains outbound tool definitions, asserts exactly one function envelope per plugin tool, and checks `transcribe_audio` parameter preservation at `function.parameters`.
  • Evidence: agents/hermes/plugin/test_register_tools.py:61-65 replaces runtime patch installers and passes a local `_FakeCtx`, whose `register_tool` stores schema without Hermes processing. agents/hermes/plugin/test_register_tools.py:68-92 asserts only pre-wrapper schema shape and audio parameters. No matches for `nemoclaw_status`, `transcribe_audio`, `Gemini`, `tool schema`, or `get_tool_definitions` were found in `test/e2e/live/hermes-e2e.test.ts`.

Workflow run details

This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge.

@wscurran wscurran added area: providers Inference provider integrations and provider behavior bug-fix PR fixes a bug or regression integration: hermes Hermes integration behavior v0.0.87 labels Jul 17, 2026
@jyaunches
jyaunches self-requested a review July 17, 2026 18:04
@jyaunches jyaunches self-assigned this Jul 17, 2026
@apurvvkumaria
apurvvkumaria self-requested a review July 17, 2026 19:31
@apurvvkumaria
apurvvkumaria merged commit f0b181c into main Jul 17, 2026
89 of 91 checks passed
@apurvvkumaria
apurvvkumaria deleted the fix/7067-hermes-plugin-tool-schema-unwrap branch July 17, 2026 21:00
@jyaunches jyaunches mentioned this pull request Jul 18, 2026
21 tasks
apurvvkumaria pushed a commit that referenced this pull request Jul 18, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Add the v0.0.87 changelog entry and align the DGX Station,
platform-support, and rebuild documentation with behavior merged since
v0.0.86.
The Station documentation retains the Deferred support status while
recording the two exact factory-image qualification profiles and the
post-reboot receipt compatibility fix from #7130.

## Changes

- Add the v0.0.87 changelog summary, including the merged Station resume
receipt fix, with links to the owning documentation pages.
- Document the exact April 2026 Colossus BaseOS and June 2026 AI
Developer Tools Station identities, validation boundaries, and permitted
host preparation.
- Synchronize those Station qualification paths into the canonical
platform matrix and generated provider/platform pages.
- Document how an OpenClaw rebuild clears stale managed-provider
session-model pins after an inference switch.

### Source summary

- [#7130](#7130) ->
`docs/changelog/2026-07-17.mdx`: Document compatibility with current
six-field and legacy three-field Station resume receipts after host
preparation.
- [#7128](#7128) ->
`docs/changelog/2026-07-17.mdx`: Document restart-safe managed DCode
startup and required Docker resource limits.
- [#7126](#7126) ->
`docs/changelog/2026-07-17.mdx`,
`docs/get-started/dgx-station-preparation.mdx`,
`ci/platform-matrix.json`: Document the two bounded Station
factory-image qualification profiles without promoting Deferred support
and synchronize the generated platform/provider references.
- [#6947](#6947) ->
`docs/changelog/2026-07-17.mdx`: Document streaming sandbox backup
archive creation.
- [#7117](#7117) ->
`docs/changelog/2026-07-17.mdx`: Document Hermes post-restore gateway
and managed MCP health verification.
- [#7109](#7109) ->
`docs/changelog/2026-07-17.mdx`,
`docs/manage-sandboxes/recover-rebuild-sandboxes.mdx`: Document stale
managed session-model pin reconciliation after rebuild.
- [#7068](#7068) ->
`docs/changelog/2026-07-17.mdx`: Document strict-provider compatibility
for Hermes tool schemas.
- [#6965](#6965) ->
`docs/changelog/2026-07-17.mdx`: Document managed vLLM download storage
estimation.
- [#7114](#7114) ->
`docs/changelog/2026-07-17.mdx`: Document preserved, redacted rebuild
diagnostics.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [x] Doc only (prose changes, no code sample modifications)
- [ ] Doc only (includes code sample changes)

## Quality Gates

- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [x] Tests not applicable — justification: Documentation-only
release-prep update; the changelog, platform-generation contracts, and
docs build validate the changed pages and links.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification

- [x] PR description includes a `Signed-off-by:` line and every commit
appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — `npx vitest run
test/generate-platform-docs.test.ts test/station-doc-ownership.test.ts
test/changelog-docs.test.ts`: 29 passed; `python3
scripts/generate-platform-docs.py --check`: all generated tables in sync
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result:
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [x] `npm run docs` builds without warnings (doc changes only)
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

---
Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added filesystem-aware managed vLLM storage preflight (cold download
sizing; interactive vs non-interactive capacity checks).
- Improved tool-schema compatibility for strict OpenAI-compatible
providers (including Gemini schema handling) using a strict single
envelope.
- Enhanced sandbox backup creation with streamed archive generation and
incremental entry validation.
- **Bug Fixes**
- Strengthened rebuild/recovery checks with Hermes sandbox health
validation and cleanup of stale managed-provider session pins.
- Persisted onboarding startup commands with required `nproc`/`nofile`
limits across sandbox recreation.
- Improved replacement-image rebuild diagnostics with bounded, redacted
output handling.
- For OpenCLAW “rebuild while preserving state,” stale model/provider
pins are cleared when appropriate.
- **Documentation**
- Expanded DGX Station GB300 no-OTA factory profile/qualification
criteria and clarified managed vLLM provider/sandbox constraints.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: providers Inference provider integrations and provider behavior bug-fix PR fixes a bug or regression integration: hermes Hermes integration behavior

Projects

None yet

4 participants