feat(xai): hermes migrate xai [--apply] — rewrite config.yaml for May 15 retirement#23320
Closed
Julientalbot wants to merge 7 commits into
Closed
feat(xai): hermes migrate xai [--apply] — rewrite config.yaml for May 15 retirement#23320Julientalbot wants to merge 7 commits into
Julientalbot wants to merge 7 commits into
Conversation
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.
Contributor
|
Salvaged into PR #29277 (merged via rebase — your commits land on main with your authorship preserved). Thanks Julien! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
hermes migrate xai [--apply] [--no-backup]— a one-shot, opt-in CLI helper to rewriteconfig.yamlso 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:
What's new in this PR (the bottom 2 commits)
hermes_cli/xai_retirement.py—apply_migration()config.yamlwithruamel.yamlround-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.RetirementIssuereturned byfind_retired_xai_refs:parent[leaf] = issue.replacementissue.reasoning_effortis non-empty (i.e. the source model was a*-non-reasoningvariant), also writes a siblingreasoning_effortkey alongside the model — this is the migration nuance that's easy to miss when swapping the model name alone.<config>.bak-pre-migrate-xai-YYYYMMDD-HHMMSSbefore rewriting; opt-out viabackup=False.ApplyResult(file_path, backup_path, issues_resolved, config_changed)so callers can render whatever feedback they want.hermes_cli/migrate.py— CLI handlerNew module to keep
main.pydispatching only.cmd_migrate_xai:hermes doctor's xAI section).--apply: backs up + rewrites; prints success summary or surfaces error and returns 1.--no-backup: opt-in only.hermes_cli/main.py— sub-parser wiringRegisters a new top-level
migrateparser with axaisub-parser, modeled on the existinggateway-style nested sub-parsers. Imports the handler module locally (same pattern ascmd_fallback).End-to-end smoke test
On a config with comments and the four retired-model slots populated:
hermes migrate xai --applyproduces:…with
config.yaml.bak-pre-migrate-xai-20260510-210033next to it. Comments, key order, type literals (the0.5float) — all preserved.Tests
17 new unit tests in
tests/hermes_cli/test_migrate_xai.py:FileNotFoundError, clean config producesconfig_changed=Falseand no backup.auxiliary.compression(openai, untouched).principal.temperaturesurvives.reasoning_effort: "none"; ambiguous bare names get the right replacement.backup=Falseskips, no-changes → no backup.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
ruamel.yamlis already inpyproject.toml(>=0.18.16,<0.19) — no new dependency.hermes migrate xai --apply.--no-backupis 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:
hermes doctorand stops there.