Skip to content

docs+feat(hermes-agent): provider compat matrix per version (Wave 4 P3-5) - #170

Closed
Ghenghis wants to merge 1 commit into
claude/agent-version-registryfrom
claude/p3-5-provider-compat-matrix
Closed

Ghenghis wants to merge 1 commit into
claude/agent-version-registryfrom
claude/p3-5-provider-compat-matrix

Conversation

@Ghenghis

Copy link
Copy Markdown
Owner

Summary

  • Adds per-version provider compatibility table — sibling to the P2-1 agent_version_registry. Frozen-tuple shape, does not mutate KNOWN_VERSIONS or HermesAgentVersion.
  • New module services/agent_version_provider_compat.py (134 LoC) with ProviderInfo (frozen dataclass), COMPAT: tuple[tuple[HermesAgentVersion, tuple[ProviderInfo, ...]], ...], and providers_for(version) accessor that returns () for unknown versions (safe fallback for active_version() is None).
  • 14 unit tests in test_agent_version_provider_compat.py (combined 27/27 with registry tests).
  • ~2,421-word doc HERMES_AGENT_PROVIDER_COMPAT_MATRIX_2026-05-09.md covering all three "provider" lanes: Hermes3D direct probes, upstream Hermes-Agent providers, and Hermes3D CLI runners (OpenCode/OpenHands).

Findings (verified by diff of both checkouts)

Lane v0.12 (v2026.4.30 @ hermes-agent-fresh) v0.13 (v2026.5.7 @ hermes-agent-v013-canary)
Hermes3D gateways/providers/ minimax, deepseek (identical) minimax, deepseek (identical)
Upstream agent/models_dev.py:PROVIDER_TO_MODELS_DEV 33 entries 33 entries (byte-identical)
Upstream agent/redact.py default OFF (os.getenv("HERMES_REDACT_SECRETS", "")) ON (os.getenv("HERMES_REDACT_SECRETS", "true"), upstream issue #21193)
New upstream files in agent/ (none are providers) — curator_backup.py, i18n.py, think_scrubber.py, tool_guardrails.py

Cross-version diff is behavioural, not structural: redaction default flips, retry/Tenacity lands, but the provider directory itself is stable. Captured in ProviderInfo.redaction_default_on per version. Surface stability mirrors Stripe's "monthly release = backward-compatible" model.

Smoke cross-references

  • Smoke 3 PASS — MiniMax: config-OK, url=https://api.minimax.io/v1/models, auth-header-present=True
  • Smoke 4 PASS — DeepSeek: env-not-configured (provider gracefully refused; PR #145/#148 fix active)
  • Smoke 5 PASS — opencode: detected=True, version_tail='1.4.3-hermes3d' (Lane C)
  • Smoke 6 PASS — openhands: detected=True, version_tail='OpenHands CLI 1.16.0' (Lane C)

Pinned by tests

  • v0.12 includes documented providers (minimax, deepseek)
  • v0.13 is a SUPERSET of v0.12 (no breaking removals)
  • Every env_var_name starts with HERMES3D_ (or documented exception)
  • No literal token shape (sk-ant-, sk-, eyJ.eyJ, base64>40) in any ProviderInfo field — OWASP A02:2021 enforcement
  • providers_for(V012) != providers_for(V013) because redaction flipped (catches a future copy-paste that loses the flip)
  • v0.12.redaction_default_on=False, v0.13.redaction_default_on=True (matches upstream issue #21193)
  • Module paths resolve to .py files on disk (FS check, no actual import — keeps tests venv-agnostic)
  • ProviderInfo is frozen (FrozenInstanceError on mutation)
  • providers_for(unknown_version) == () safe fallback
  • COMPAT is tuple[tuple[..., tuple[...]]] (structural immutability)
  • Endpoint URLs pinned (api.minimax.io, api.deepseek.com /v1/models)
  • auth_header == "Authorization" for all current providers

Sources cited

  1. OWASP A02:2021 Cryptographic Failures — https://owasp.org/Top10/2021/A02_2021-Cryptographic_Failures/ — env-var-NAMES-only convention; failure path that does NOT echo env var name (matches Squad G PR fix(deepseek): explicit RuntimeError on missing env (Squad G / E2E Blocker Elimination) #145/fix(minimax): explicit RuntimeError on missing env (Squad G parity / Wave synthesis 2026-05-09) #148 fix)
  2. Stripe API versioning — https://docs.stripe.com/api/versioning — per-version stability model; per-version-pin convention for the immutable COMPAT tuple
  3. NousResearch/hermes-agent (upstream) — agent/models_dev.py, agent/redact.py
  4. P2-1 registry (commit afd8999) — services/agent_version_registry.py
  5. HERMES_AGENT_V013_CANARY_SMOKE_2026-05-09.md — observed test results

Test plan

  • pytest 04_testing/pytest/unit/test_agent_version_registry.py 04_testing/pytest/unit/test_agent_version_provider_compat.py -v → 27/27 pass
  • No live HTTP calls in tests; no actual import of upstream agent modules
  • git status shows only the three intended files (no concurrent-agent leakage)
  • Doc covers TL;DR matrix, per-provider reference (file:line, signature, auth header NAME only), URL, env var name, smoke result, migration callouts, caller table, OWASP + Stripe rationale

What this PR does NOT do

  • Does not modify services/agent_version_registry.py (frozen, P2-1)
  • Does not vendor or copy any upstream agent/*_adapter.py into Hermes3D
  • Does not change gateways/providers/minimax.py or deepseek.py behaviour — both are read-only here
  • Does not call any provider live in tests
  • Does not document the upstream-side models_dev.py:PROVIDER_TO_MODELS_DEV registry in code (would duplicate 33 lines of upstream data and rot fast). Lane B is documented narratively in §2 only

Hermes evidence chain: PASS

  • Task ID: P3-5-PROVIDER-COMPAT-MATRIX
  • hermes_run_gate: deferred (pure docs + small registry sibling, no policy / behavioural change)
  • Hermes locks: acquired by claude-lead-p3-5-providers (3 files), released on PR open
  • LoC: 134 source + 260 tests + 2421-word doc

🤖 Generated with Claude Code

…3-5)

Adds per-version provider compatibility table sibling to the P2-1 agent_version_registry. Frozen-tuple shape, no mutation of P2-1's registry. Documents which providers are reachable on Hermes Agent v0.12 vs v0.13, what redaction layer applies, and where each provider adapter is imported from.

Findings: Hermes3D-side direct probes (gateways/providers/) are minimax + deepseek, identical between v0.12 and v0.13 (those modules are Hermes3D code, not vendored from upstream). Smoke 3 + Smoke 4 PASS (2026-05-09). Upstream agent/models_dev.py:PROVIDER_TO_MODELS_DEV — 33 entries, byte-identical between v0.12 and v0.13. Cross-version diff is BEHAVIOURAL: agent/redact.py default flipped OFF -> ON in v0.13 (upstream issue #21193). OpenCode + OpenHands are CLI runners (services/code_history.py), not LLM providers.

Module: services/agent_version_provider_compat.py — frozen ProviderInfo dataclass, COMPAT tuple-of-tuples, providers_for(version). Doc: HERMES_AGENT_PROVIDER_COMPAT_MATRIX_2026-05-09.md (~2400 words). Tests: 14/14 pass; combined with registry tests 27/27 pass.

Sources cited: OWASP A02:2021 Cryptographic Failures (env-var-NAMES-only convention; RuntimeError without env-var-name leak); Stripe API versioning (per-version stability model).

LoC: 134 source + 260 tests + 2421-word doc. Handoff: P3-6 can read providers_for(active_version()) for proof-event version tagging.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented May 10, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2507468e-1288-4b38-ab7f-04dbbf9a62ce

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/p3-5-provider-compat-matrix

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

@Ghenghis
Ghenghis deleted the branch claude/agent-version-registry May 10, 2026 01:39
@Ghenghis Ghenghis closed this May 10, 2026
Ghenghis added a commit that referenced this pull request May 10, 2026
…3-5) [re-target of #170] (#174)

* feat(hermes-agent): promote v0.13 to production default (Wave 1 P1-5; 7/7 gates green)

Wave 1 of the v0.13 production promotion swarm cleared all 7 hard gates.
This PR flips the resolver default from v0.12 (hermes-agent-fresh) to
v0.13 (hermes-agent-v013-canary). v0.12 remains the opt-in fallback via
HERMES_AGENT_CHECKOUT=G:/Github/hermes-agent-fresh.

Hard gates (all PASS, evidence below)
1. MiniMax accepted=true       — P1-1 (ev_84c2ba93c25d4017)
2. DeepSeek accepted=true      — P1-1 (ev_6fa1536b411822db)
3. Canary runtime smoke passes — P1-2 (8/8 imports, 38-subcommand CLI,
   10 MCP tools, redaction default-ON per upstream PR #21193)
4. v0.12 rollback path proven  — P1-2 (resolver mid-process flip 4/4
   reads correct; production HEAD bit-identical pre/post)
5. No secret leak              — P1-1 + P1-4 (only env-var NAMES + host
   labels in evidence; auth_scheme is static "Authorization: Bearer
   <redacted>"; OWASP A09 review clean)
6. No v0.12 regression         — P1-2 (production checkout bit-identical;
   git status --short empty post-run)
7. BLK-013 fixed by PR #159    — P1-4 (bounded CLI runner endpoint
   shipped with --network=none + --read-only + --cap-drop=ALL +
   sha256-only stderr; 6/6 new tests + 52/52 adjacent regression PASS)

Bonus discovery (P1-3)
- Upstream PR #21561 already merged the Windows TUI signal.SIGPIPE/
  SIGHUP guard on 2026-05-08 (uses hasattr() pattern + SIGBREAK
  fallback). Canary at v2026.5.7 (498bfc7, 2026-05-07) predates this
  fix, so the TUI/PTY surface still requires advancing the canary
  checkout to >= e93bfc6c to gain native Windows TUI support. Core CLI
  + MCP + redaction + provider chat all work TODAY without that
  advance, which is why this promotion is safe.

Patch
- DEFAULT_AGENT_CHECKOUT now points to v0.13 (canary path).
- New V012_FALLBACK_CHECKOUT constant exposes the v0.12 path for
  operators + tests that need explicit fallback semantics.
- CANARY_AGENT_CHECKOUT retained as alias for back-compat.

Tests added/updated (11/11 PASS)
- test_default_is_v013_post_promotion: env unset → v0.13
- test_v012_fallback_via_env: env=hermes-agent-fresh → v0.12
- test_resolver_constants_are_correct: DEFAULT == CANARY == v0.13;
  V012_FALLBACK == hermes-agent-fresh
- test_a5_per_call_env_flip: post-promotion semantic (v0.13 ↔ v0.12)
- test_a4_agent_updates_repo_path_per_call: same semantic via
  agent_updates._repo_path()
- test_v013_default_when_env_unset: route helper + resolver agree
- (4 source-level pin tests retained from PR #155)

Verification
- py_compile: OK
- Focused tests: 11/11 pass
- Pre-push hook: passed

Rollback
- Operators set HERMES_AGENT_CHECKOUT=G:/Github/hermes-agent-fresh in
  the FastAPI process env to revert to v0.12 mid-process (no restart;
  per-call resolver from PR #155).
- Or revert this PR (1 commit) to restore v0.12 as the file-level
  default.
- Production v0.12 checkout at G:/Github/hermes-agent-fresh remains
  byte-identical (HEAD 73bf3ab1, v2026.4.30, status clean) — never
  modified by canary work.

Companion PRs
- PR #155 (8544bbc): per-call env-switch resolver (Wave A4 + A5)
- PR #157 (b8277db): canary smoke results 7/1/0
- PR #158 (5a32fe0): production v0.13 + multi-version action plan
- PR #159 (open): BLK-013 bounded task — provides hard gate 7

Hermes-Agent-Only Wave 1 swarm provenance
- P1-1 Live provider probes: PASS (ev_84c2ba93c25d4017 + ev_6fa1536b411822db)
- P1-2 Canary runtime + production-untouched: PASS (5/5 sub-checks)
- P1-3 Upstream Windows guard: ALREADY MERGED upstream (PR #21561)
- P1-4 BLK-013: PR #159 OPEN (6/6 + 52/52 regression PASS)
- P1-5 Promotion: this PR

References
- Upstream v0.13.0 release: https://github.com/NousResearch/hermes-agent/releases/tag/v2026.5.7
- Upstream redaction default-ON: NousResearch/hermes-agent#21193
- Upstream Windows guard: NousResearch/hermes-agent#21561
- 12-Factor App rule III (config in env): https://12factor.net/config

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(hermes-agent): version registry for v0.12 + v0.13 (Wave 2 P2-1)

Adds services/agent_version_registry.py — a frozen-dataclass registry
(KNOWN_VERSIONS = (V012, V013)) of known Hermes Agent versions and
their feature flags (redaction_default_on, has_kanban,
has_heartbeat_reclaim, has_zombie_detection,
has_pluggable_providers_dir). Pairs with agent_checkout.py: that module
resolves which path is active right now; this one says what we know
about each version we've shipped. active_version() reads the live
checkout path through hermes_agent_checkout() so per-call env-flips
(PR #155 / Wave A5) propagate without restart, and returns None if the
operator points HERMES_AGENT_CHECKOUT at a custom fork.

Reads agent_checkout module-level constants only; does not edit it.

Pinned by tests:
- KNOWN_VERSIONS = (v0.12@v2026.4.30, v0.13@v2026.5.7) in order.
- v0.13.redaction_default_on=True (NousResearch/hermes-agent#21193,
  Wave A3 verified).
- v0.12.redaction_default_on=False (Wave 2 prior swarm Agent 2).
- active_version() == v0.13 with env unset (post-PR #160 default).
- active_version() == v0.12 when env=hermes-agent-fresh.
- active_version() is None for unknown checkouts.
- FrozenInstanceError on any field mutation (no cross-version leak).

LoC: 89 lines source (67 non-blank/non-comment) + 114 lines tests.
Tests: 13/13 pass; combined with test_agent_checkout_resolver.py 24/24 pass.

References:
- Python @DataClass(frozen=True): https://docs.python.org/3/library/dataclasses.html#frozen-instances
- Django AppConfig metadata pattern: https://docs.djangoproject.com/en/5.1/ref/applications/

Handoff: P2-5 (compat matrix) reads KNOWN_VERSIONS for capability rows;
P2-6 (proof events) reads active_version().label/upstream_tag for the
version_tag field on every event.

* docs+feat(hermes-agent): provider compat matrix per version (Wave 4 P3-5)

Adds per-version provider compatibility table sibling to the P2-1 agent_version_registry. Frozen-tuple shape, no mutation of P2-1's registry. Documents which providers are reachable on Hermes Agent v0.12 vs v0.13, what redaction layer applies, and where each provider adapter is imported from.

Findings: Hermes3D-side direct probes (gateways/providers/) are minimax + deepseek, identical between v0.12 and v0.13 (those modules are Hermes3D code, not vendored from upstream). Smoke 3 + Smoke 4 PASS (2026-05-09). Upstream agent/models_dev.py:PROVIDER_TO_MODELS_DEV — 33 entries, byte-identical between v0.12 and v0.13. Cross-version diff is BEHAVIOURAL: agent/redact.py default flipped OFF -> ON in v0.13 (upstream issue #21193). OpenCode + OpenHands are CLI runners (services/code_history.py), not LLM providers.

Module: services/agent_version_provider_compat.py — frozen ProviderInfo dataclass, COMPAT tuple-of-tuples, providers_for(version). Doc: HERMES_AGENT_PROVIDER_COMPAT_MATRIX_2026-05-09.md (~2400 words). Tests: 14/14 pass; combined with registry tests 27/27 pass.

Sources cited: OWASP A02:2021 Cryptographic Failures (env-var-NAMES-only convention; RuntimeError without env-var-name leak); Stripe API versioning (per-version stability model).

LoC: 134 source + 260 tests + 2421-word doc. Handoff: P3-6 can read providers_for(active_version()) for proof-event version tagging.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Ghenghis
Ghenghis deleted the claude/p3-5-provider-compat-matrix branch May 10, 2026 01:44
@Ghenghis

Copy link
Copy Markdown
Owner Author

Auto-closed when base claude/agent-version-registry was deleted on squash-merge of #162. Content was re-targeted onto feat/hermes3d-7-complete-gui-repo-wiring and merged via PR #174 (commit 50e057b).

Ghenghis added a commit that referenced this pull request May 10, 2026
…entions (W8-6) (#187)

* proof(audit): retroactive truth-gate for PRs #136-#178 (W7-1 follow-up)

Closes audit findings F-149-01 (P0), F-CI-EMPTY-01 (P1), F-CI-CRBOT-01 (P2).

PR #149's recovery_controller.py (1,129 LoC RC v2 foundation) and 9 sibling
PRs were merged into feat/hermes3d-7-complete-gui-repo-wiring with empty
statusCheckRollup. This file captures ex-post-facto pytest evidence against
the integration HEAD (d1334ed) so the merged work has redacted, archivable
proof per the ITIL incident-management evidence-of-fix pattern.

Targeted suites (56/56 green, all directly close F-149-01):
  - recovery_controller_freeze:           7 passed   (3.34s)
  - agent_checkout + v012/v013 pins:     27 passed   (3.47s)
  - canary_dirt_filter:                  22 passed   (0.13s)

Wider unit scan: 1146 passed / 11 failed / 5 skipped (98.6% pass rate).
All 11 failures are environmental (MCP workspace path mismatch in
test_code_operator, firmware-inventory state drift in
test_source_runtime_contracts) and pre-date the audited PR window.
Verdict: PARTIAL - honest gap documented per the persistence rule.

Hermes evidence chain: PASS
Task ID: W8-6-RETRO-PROOF-2026-05-09
hermes_run_gate: pytest 4-suite green; redacted-evidence JSON shipped

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(contributing): PR-body conventions for tests-added + re-target tag

Adopts two cosmetic-but-recurring PR-body conventions surfaced by W7-1's
audit, so future reviewers don't have to guess file-vs-case counts or
which branch a stacked PR was rebased onto.

- Tests-added: write "N file(s), M cases - all green" (closes F-DRIFT-143-01).
- Stacked-on / Reland-of: required on PRs not targeting develop / main
  (codifies the verified-equivalent pattern from W7-2's #168 -> #173, #170
  -> #174 reland chain).

Source: GitHub PR best-practices guidance on stacked PRs and discoverable
context (https://docs.github.com/en/pull-requests).

Hermes evidence chain: PASS
Task ID: W8-6-RETRO-PROOF-2026-05-09

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bastizol-wq

Copy link
Copy Markdown

Re: “docs+feat(hermes-agent): provider compat matrix per version (Wave 4 P3-5)” — one practical fix is to treat tools like untrusted inputs and validate the contract first.

We’ve had good luck turning this into a small policy step: validate tool description + transport, then only allow the call if checks pass.

ATCP is an API-first gate that evaluates a tool/OpenAPI and returns a structured allow/warn/block result.

ATCP OpenAPI: https://api.sp-ai.io/v1/openapi.yaml

If you’re already on OpenAPI, starting with a tiny evaluate endpoint + receipt logging is a low-effort step.

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.

2 participants