Skip to content

fix(cronjob): accept bare model string in schema and _resolve_model_override - #68587

Closed
webtecnica wants to merge 2 commits into
NousResearch:mainfrom
webtecnica:fix/68380-cron-model-drop
Closed

fix(cronjob): accept bare model string in schema and _resolve_model_override#68587
webtecnica wants to merge 2 commits into
NousResearch:mainfrom
webtecnica:fix/68380-cron-model-drop

Conversation

@webtecnica

Copy link
Copy Markdown
Contributor

Fixes #68380

Problem

cronjob action=update silently drops the model field when the LLM sends a flat string (e.g. "gpt-4") instead of the declared object shape {"model": "gpt-4"}. The provider updates fine because it is a top-level string, but _resolve_model_override guards on isinstance(model_obj, dict) and returns (None, None) for strings — the model value is lost entirely while the tool reports success.

Fix (two parts)

  1. Schema: Change model from {provider, model} object to a flat string. Add top-level provider and base_url string params, matching the function signature and the UX: model drift guardrail silently breaks all unpinned cron jobs on model change #59031 guardrail's advertised syntax.

  2. _resolve_model_override: Accept both shapes:

    • {"model": "...", "provider": "..."} — existing object shape (unchanged)
    • "gpt-4" — bare string treated as model name, no provider override

Regression tests (5)

Added 5 new tests to TestResolveModelOverride (8 total):

  • test_bare_string_model_returns_none_provider"anthropic/claude-haiku-4.5"(None, "anthropic/claude-haiku-4.5")
  • test_bare_string_model_whitespace_stripped" gpt-4 "(None, "gpt-4")
  • test_bare_string_model_empty_returns_none_none" "(None, None)
  • test_dict_model_still_works — dict path unaffected
  • test_none_returns_none_none — None path unaffected

All 82 tests in tests/tools/test_cronjob_tools.py pass.

…verride

Issue NousResearch#68380 — cronjob action=update silently drops .

The JSON schema declared  as an object ({provider, model})
while the Python handler expected a flat string. When an agent sent
a flat model string (the shape the handler reads), schema validation
stripped it, and  returned (None, None) for
non-dict inputs — the model was silently lost.

Fix (two parts):

1. Schema: Change  from {provider, model} object to a flat
   string. Add top-level  and  string params,
   matching the function signature and the NousResearch#59031 guardrail syntax.

2. _resolve_model_override: Accept bare model strings in addition
   to dicts. A bare string is treated as model name with no provider
   override. Whitespace-stripped; empty strings return (None, None).

Regression tests (5): bare string, whitespace-stripped, empty string,
dict path unchanged, None unchanged.
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/cron Cron scheduler and job management labels Jul 21, 2026
@webtecnica
webtecnica force-pushed the fix/68380-cron-model-drop branch from 22cfdf2 to 41909eb Compare July 21, 2026 14:28

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for tracing the earlier schema/handler mismatch. Current main has since adopted a different, deliberate model: per-job inference pins are user-owned rather than agent-callable.

Problems

  • tools/cronjob_tools.py:1083-1087 intentionally ignores agent-supplied model, provider, and base_url, so restoring the schema fields in this PR would let an agent redirect unattended spend again.
  • tests/tools/test_cronjob_tools.py:543-608 already verifies both schema exclusion and preservation of existing user-owned pins. The helper this PR extends was removed by d464ae3652cee225bc667c6b64caf749bfb55965 as part of that design.

Suggested changes

  • Please target the supported pinning surfaces instead: dashboard, hermes cron create/edit --model/--provider, jobs.json, or the cron-fleet cron.model / cron.model_provider configuration added in d464ae3652.

Automated hermes-sweeper review.

Comment thread tools/cronjob_tools.py
@@ -1023,19 +1033,16 @@ def cronjob(
"description": "Optional ordered list of skill names to load before executing the cron prompt. On update, pass an empty array to clear attached skills."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current main deliberately removed agent-facing model/provider/base_url pins in d464ae3652: tools/cronjob_tools.py:1083-1087 now ignores those arguments so an agent cannot redirect unattended spend. Please do not restore this schema surface; use the user-owned CLI/dashboard pinning paths instead.

@teknium1 teknium1 added sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 30, 2026
@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Summary

Two PRs address the former schema/handler mismatch in #68380: #68397 adds bare-string resolver compatibility and helper tests, while #68587 additionally exposes flat model, provider, and base_url schema fields. Current main instead resolves the issue by removing those agent-facing pin fields and moving repinning to user-owned CLI/dashboard paths.

Related pull requests

Duplicates

#68397 and #68587 substantially duplicate the bare-string resolver change and helper tests; #68587 is the broader superseding diff because it also changes the exposed schema.

Suggested consolidation

Close #68587 as already implemented on main through the alternative resolution in d464ae3652cee225bc667c6b64caf749bfb55965 (PR #73532), per the contributor review citing tools/cronjob_tools.py:1083-1087 and tests/tools/test_cronjob_tools.py:543-608; the supported replacement is user-owned CLI/dashboard pinning rather than restoring agent-facing fields. Keep #68397 closed as the narrower duplicate and superseded implementation.

Complex graph

flowchart LR
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
    classDef best stroke-width:3px,stroke:#b45309
    classDef target stroke-width:3px,stroke:#4338ca
    I68380(["issue #68380 (closed)"])
    subgraph Dup68397 ["PRs duplicating each other"]
        P68397["PR #68397 (closed)"]
        P68587["PR #68587 (open)"]
    end
    P68587 -->|best fix| I68380
    class I68380 closed
    class P68397 closed
    class P68587 open
    class P68587 best
    class P68587 target
    click I68380 "https://github.com/NousResearch/hermes-agent/issues/68380"
    click P68397 "https://github.com/NousResearch/hermes-agent/pull/68397"
    click P68587 "https://github.com/NousResearch/hermes-agent/pull/68587"
Loading

Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).

Cross-PR triage: Reviewed 2 pull requests and 1 issue in this complex. Each diff was read against this issue; Assessment working set: 9 kB of PR diffs, 8 kB of issue/PR text, 3 kB of discussion (4 comments), 3 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the work here @webtecnica — closing this one on policy grounds rather than code quality. PR #73532 deliberately removed model/provider from the agent-facing cronjob tool schema: per-job inference pins are user-owned (dashboard, hermes cron create/edit --model/--provider, or jobs.json), so the agent can never silently re-route cron spend. Re-exposing the field in the schema would reverse that boundary. The stale remediation text that pointed agents at the removed parameter was fixed in #87472 — every drift/missing-model alert now advertises the supported hermes cron edit path.

@teknium1 teknium1 closed this Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cron Cron scheduler and job management P2 Medium — degraded but workaround exists sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: cronjob action=update silently drops model (schema declares object, handler reads string) — provider updates, model doesn't

4 participants