Skip to content

feat(transport): HERMES_TOOL_USE_ENFORCEMENT=required injection (closes #115)#116

Merged
PowerCreek merged 1 commit into
mainfrom
tool-use-enforcement-required-115
May 27, 2026
Merged

feat(transport): HERMES_TOOL_USE_ENFORCEMENT=required injection (closes #115)#116
PowerCreek merged 1 commit into
mainfrom
tool-use-enforcement-required-115

Conversation

@PowerCreek

Copy link
Copy Markdown

Closes #115. Opt-in env knob (default off) that forces tool_choice: "required" when tools attached. Companion to devagentic#315 (initiative preamble) — preamble tells model what to do; this tells API how to constrain. Both build_kwargs paths in chat_completions transport wired via shared helper. Doctor probe surfaces active setting. 18 new tests + 128 total green. Ships in off-by-default mode per #115's sequencing — operator enables when ready.

#115)

Companion to devagentic#315 (initiative preamble). When operator
sets ``HERMES_TOOL_USE_ENFORCEMENT=required``, the chat_completions
transport injects ``tool_choice: "required"`` on every dispatch
where tools are attached — the model-layer enforcement that closes
the gap devagentic#315's soft-signal preamble leaves open.

## Behavior

- Unset / empty / unknown value → default behavior unchanged (no
  ``tool_choice`` injected by hermes)
- ``HERMES_TOOL_USE_ENFORCEMENT=required`` + tools attached →
  ``tool_choice: "required"`` set on the API kwargs
- Tools NOT attached → no injection (sending ``tool_choice=required``
  with empty tools is a 400 on most providers)
- Caller-supplied ``tool_choice`` already on kwargs → no override
  (the dispatcher-tier signal wins; env is a session-tier default)

Per devagentic#203 §1.3 — hermes owns model-call-shape decisions
(per-call enforcement). Devagentic's models.json
``default_tool_choice`` is the dispatcher-tier default; this env is
the session-tier override.

## Where it fires

Both build_kwargs paths in ``chat_completions.py``:
- Legacy fallback path (unregistered providers)
- Provider-profile path (known providers via providers/ registry)

Shared helper ``_maybe_inject_required_tool_choice(api_kwargs,
tools)`` keeps the two sites in sync.

## Doctor probe

New ``_check_tool_use_enforcement_env`` surfaces the active setting
— silent when unset, ``check_ok`` on ``required``, ``check_warn``
with valid-values hint on typos. Mirrors the silent-when-irrelevant
pattern from #95 / #96 / persona-deferred.

## Tests

- 18 new tests in tests/agent/test_tool_use_enforcement.py:
  resolver returns None/required/case-insensitive/unknown (8
  parametrized), injection happy path (1), no-inject-when-unset (1),
  no-inject-when-no-tools (1 covering both None and empty list),
  does-not-clobber-existing-tool_choice (1), no-inject-on-unknown
  (1), doctor silent-when-unset (1), doctor check_ok on required
  (1), doctor check_warn on unknown (1).
- 128 total green across affected suites (new + doctor + provider/
  intent/persona/tools-subset probes). No regression.

## Sequencing per #115 body

The issue says "Land after devagentic#315 Phase 1 has deployed +
been observed. If the preamble alone closes the reliability gap to
operator satisfaction, this issue may not need to ship."

This PR ships the env-knob in opt-in OFF-by-default mode, so:
- Operators can enable it the moment they observe NousResearch#315's preamble
  is insufficient (no further hermes-side dev cycle needed)
- Default behavior unchanged → zero risk to non-client-tier sessions
- Doctor probe surfaces the active state so operators can confirm
  enablement at boot

Saves the round-trip of waiting + then dev'ing once the signal
arrives.
@PowerCreek PowerCreek merged commit 52ca1f9 into main May 27, 2026
@PowerCreek PowerCreek deleted the tool-use-enforcement-required-115 branch May 27, 2026 00:34
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.

companion to devagentic#315: hermes-side tool_use_enforcement=required setting for client-tier sessions

1 participant