Skip to content

feat(xai): hermes migrate xai [--apply] — rewrite config.yaml for May 15 retirement#23320

Closed
Julientalbot wants to merge 7 commits into
NousResearch:mainfrom
Julientalbot:feat/xai-migrate-cli
Closed

feat(xai): hermes migrate xai [--apply] — rewrite config.yaml for May 15 retirement#23320
Julientalbot wants to merge 7 commits into
NousResearch:mainfrom
Julientalbot:feat/xai-migrate-cli

Conversation

@Julientalbot

Copy link
Copy Markdown
Contributor

Summary

Adds hermes migrate xai [--apply] [--no-backup] — a one-shot, opt-in CLI helper to rewrite config.yaml so it stops referencing xAI models being retired on May 15, 2026. Pairs with #23278 (doctor + chat-startup warning) — that PR tells users what needs to change; this PR is the actual fix-it button.

Stacked on top of #23278

This PR's branch contains the 3 commits from #23278 plus 2 new commits:

3dd1d620a feat(cli): hermes migrate xai [--apply] [--no-backup]                  ← new
9322cf948 feat(xai): apply_migration — rewrite config.yaml in-place via ruamel    ← new
2e6bf2177 feat(cli): warn about retired xAI models at chat startup                ← from #23278
0f776094a feat(doctor): surface xAI model retirement in hermes doctor             ← from #23278
bf9a09abf feat(xai): detect retired xAI models (May 15, 2026)                     ← from #23278

What's new in this PR (the bottom 2 commits)

hermes_cli/xai_retirement.pyapply_migration()

  • Reads config.yaml with ruamel.yaml round-trip (YAML(typ="rt"), preserve_quotes=True) so comments, key order, indentation, and scalar types are preserved. Treats config.yaml as a user-edited file, not a data dump.
  • For each RetirementIssue returned by find_retired_xai_refs:
    • sets parent[leaf] = issue.replacement
    • if issue.reasoning_effort is non-empty (i.e. the source model was a *-non-reasoning variant), also writes a sibling reasoning_effort key alongside the model — this is the migration nuance that's easy to miss when swapping the model name alone.
  • Writes a timestamped backup <config>.bak-pre-migrate-xai-YYYYMMDD-HHMMSS before rewriting; opt-out via backup=False.
  • Returns an ApplyResult(file_path, backup_path, issues_resolved, config_changed) so callers can render whatever feedback they want.
  • Empty-issues list, missing slot, or empty config → no-op (no backup written, no rewrite).

hermes_cli/migrate.py — CLI handler

New module to keep main.py dispatching only. cmd_migrate_xai:

  • Always prints the diagnostic block (same format as hermes doctor's xAI section).
  • Default = dry-run: prints what would change, returns 0.
  • --apply: backs up + rewrites; prints success summary or surfaces error and returns 1.
  • --no-backup: opt-in only.

hermes_cli/main.py — sub-parser wiring

Registers a new top-level migrate parser with a xai sub-parser, modeled on the existing gateway-style nested sub-parsers. Imports the handler module locally (same pattern as cmd_fallback).

End-to-end smoke test

On a config with comments and the four retired-model slots populated:

# Hermes config — manually crafted for migration smoke test
principal:
  provider: xai
  model: grok-4-1-fast-non-reasoning  # this should migrate
  temperature: 0.5
auxiliary:
  vision:
    provider: xai
    model: grok-4-fast      # ambiguous variant
delegation:
  model: grok-code-fast-1   # retiring

hermes migrate xai --apply produces:

# Hermes config — manually crafted for migration smoke test
principal:
  provider: xai
  model: grok-4.3                     # this should migrate
  temperature: 0.5
  reasoning_effort: none
auxiliary:
  vision:
    provider: xai
    model: grok-4.3         # ambiguous variant
delegation:
  model: grok-4.3           # retiring

…with config.yaml.bak-pre-migrate-xai-20260510-210033 next to it. Comments, key order, type literals (the 0.5 float) — all preserved.

Tests

17 new unit tests in tests/hermes_cli/test_migrate_xai.py:

  • No-op paths: empty config, empty issues list, missing file → FileNotFoundError, clean config produces config_changed=False and no backup.
  • Surgical replacement: principal, auxiliary.vision, delegation, plugins.image_gen.xai. auxiliary.compression (openai, untouched). principal.temperature survives.
  • Migration semantics: non-reasoning variant adds reasoning_effort: "none"; ambiguous bare names get the right replacement.
  • Round-trip preservation: top-of-file comment, inline comments on unmodified lines, top-level key order.
  • Backup behavior: default backup written, filename prefix correct, backup=False skips, no-changes → no backup.
  • Idempotence: applying twice is safe — the second pass finds zero issues and does nothing.

50/50 tests pass when combined with the test suite from #23278 (pytest tests/hermes_cli/test_xai_retirement.py tests/hermes_cli/test_migrate_xai.py).

Backward compatibility

  • Pure addition. No public API changes, no config schema changes.
  • ruamel.yaml is already in pyproject.toml (>=0.18.16,<0.19) — no new dependency.
  • The migrate command is opt-in: nothing happens to a user's config unless they explicitly run hermes migrate xai --apply.
  • Default backup is on; --no-backup is the only way to skip it.

Why one PR per layer

PR #23278 (diagnostic) and this PR (action) could've been a single 700-LoC PR. Splitting them gives:

  • A useful diagnostic available even if review on the rewriter takes longer (the doctor + startup warning ship value on day 1).
  • A smaller second PR focused on the one tricky bit: ruamel round-trip semantics. Easier to review the YAML-rewriting logic in isolation.
  • Clear answer to "what if the user just wants to know without me touching their config?" — that user runs hermes doctor and stops there.

Add hermes_cli.xai_retirement module that walks a Hermes config and
flags references to models being retired by xAI on May 15, 2026 per
the official migration guide.

Pure logic + dataclass, no I/O — testable in isolation and reusable
from a future hermes migrate xai sub-command.

Mappings (per https://docs.x.ai/developers/migration/may-15-retirement):
  - grok-4 / grok-4-0709                  -> grok-4.3
  - grok-4-fast{,-reasoning,-non-reasoning}    -> grok-4.3 (+reasoning_effort=none for non-reasoning)
  - grok-4-1-fast{,-reasoning,-non-reasoning}  -> grok-4.3 (+reasoning_effort=none for non-reasoning)
  - grok-code-fast-1                      -> grok-4.3
  - grok-imagine-image-pro                -> grok-imagine-image-quality

Slots scanned: principal.model, auxiliary.<any>.model (introspective),
delegation.model, tts.xai.model, plugins.image_gen.xai.model. Provider
prefix x-ai/ is normalized.

33 unit tests covering edge cases (empty/non-dict config, valid models,
ambiguous variants, all retired slots, formatter).
Add a new section in run_doctor that lists retired xAI model
references found in the active config and points the user at the
official xAI migration guide.

Each retired reference shows its config path (principal.model,
auxiliary.<slot>.model, delegation.model, tts.xai.model, or
plugins.image_gen.xai.model), the recommended replacement, and
whether reasoning_effort needs to be set (for non-reasoning variants
that map to grok-4.3 + reasoning_effort=none).

Findings are appended to manual_issues so the final doctor summary
reminds the user to update their config.yaml manually (no automatic
YAML rewriting in this PR — preserves comments, key order, types).

Wrapped in try/except so doctor still completes if load_config or
the retirement module raise unexpectedly.
Print a non-blocking stderr warning at the top of cmd_chat when the
active config still references xAI models scheduled for retirement
on May 15, 2026. Each line includes the config path, the recommended
replacement, and the reasoning_effort to set for non-reasoning
variants. Points to hermes doctor for full diagnostic.

Wrapped in try/except — never blocks startup. After May 15 the
upstream xAI API will return a clear error anyway; this is purely a
heads-up to give users time to migrate before that happens.
…round-trip

Extends hermes_cli.xai_retirement with apply_migration(config_path,
issues, backup=True), used by the upcoming `hermes migrate xai`
sub-command.

Uses ruamel.yaml round-trip mode so that comments, key order,
indentation, quoting style, and scalar types are preserved on
rewrite — config.yaml is treated as a user-edited file, not a
data dump.

Behavior:
  - Each issue rewrites parent[leaf] to issue.replacement
  - When issue.reasoning_effort is set (non-reasoning variants
    that map to grok-4.3), a sibling reasoning_effort key is
    added/updated alongside the model
  - Empty issues list or missing slots are no-ops (no backup,
    no rewrite)
  - When changes occur, a timestamped backup
    (.bak-pre-migrate-xai-YYYYMMDD-HHMMSS) is written first
    unless backup=False

17 unit tests cover dry-run/no-op, surgical replacement (each
slot), comment + key-order preservation, backup creation, and
idempotence (apply twice → no-op the second time).
Adds a new `migrate` top-level sub-command that delegates to
`migrate xai` for now. xAI handler:

  - Default: dry-run. Lists every retired xAI model reference
    found in config.yaml, with the recommended replacement and
    reasoning_effort hint, and points to the official xAI
    migration guide.
  - --apply: rewrites config.yaml in-place (via the ruamel
    round-trip apply_migration helper from hermes_cli.xai_retirement).
    A timestamped backup is created automatically.
  - --no-backup: skips the backup when applying (opt-in only —
    the safe default keeps a copy).

Together with the doctor + chat-startup warnings already in
this stack, this gives users three escalating signals before
the May 15, 2026 retirement date: green check / warning at
chat startup / actionable migration command.
@alt-glitch alt-glitch added type/feature New feature or request P2 Medium — degraded but workaround exists comp/cli CLI entry point, hermes_cli/, setup wizard provider/xai xAI (Grok) labels May 10, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Salvaged into PR #29277 (merged via rebase — your commits land on main with your authorship preserved). Thanks Julien!

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

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists provider/xai xAI (Grok) type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants