{"repo":"NousResearch/hermes-agent","public_id":"55380","display_label":"delegate_task not honoring delegation configuration settings","summary":"The members concern delegate_task apparently not respecting delegation config: one issue reports it as hardcoded to xiaomi, and two pull requests propose making the active config authoritative for limits and merging persistent and runtime config sources. Details beyond the titles are not shown, so the exact relationship between them is unconfirmed.","subsystem":"agent","counts":{"members":3,"open_issues":0,"open_issues_distinct":0,"open_prs":0,"closed_issues":1,"merged_prs":1,"attempt_prs":1},"landed_fix":{"status":"merged_to_main","basis":"structural","pr":60577,"merged_at":"2026-07-08T00:17:39+00:00"},"resolution":{"state":"unresolved","by":null},"freshness":{"state":"verified","last_verified_at":"2026-07-08T00:17:39+00:00","is_stale":false},"grouping":{"backbone":"STRUCTURAL_SPANNING","link_density":0.6666666666666666},"fix_edges":[{"issue_number":18946,"pr_number":60577,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false,"pr_merged_at":"2026-07-08T00:17:39+00:00"},{"issue_number":51435,"pr_number":60577,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false,"pr_merged_at":"2026-07-08T00:17:39+00:00"},{"issue_number":55380,"pr_number":60577,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false,"pr_merged_at":"2026-07-08T00:17:39+00:00"},{"issue_number":57930,"pr_number":60577,"tier":"verified","basis":"superseded_ref","confidence":0.9,"recoverable_from_timeline":false,"pr_merged_at":"2026-07-08T00:17:39+00:00"}],"members":[{"kind":"issue","number":55380,"title":"Bug: delegate_task ignores delegation config — hardcoded to xiaomi","url":null,"state":"closed"},{"kind":"pr","number":55478,"title":"fix(delegate): merge persistent + runtime delegation config sources","url":null,"state":"closed","close_reason":{"refs":[{"kind":"pr","value":"#60577","number":60577},{"kind":"pr","value":"#59982","number":59982}],"category":"implemented_elsewhere","implication":"superseded"},"merged":false},{"kind":"pr","number":60577,"title":"fix(delegation): make active config authoritative for delegation limits","url":null,"state":"merged","close_reason":{"category":"merged"},"merged":true,"is_fix_pr":true,"fix_tier":"verified","files_changed":["tests/tools/test_delegate.py","tools/delegate_tool.py"],"fix_hunks":[{"file":"tests/tools/test_delegate.py","hunks":["@@ -13,6 +13,7 @@\n import os\n import threading\n import time\n+import types\n import unittest\n from unittest.mock import MagicMock, patch\n ","@@ -21,6 +22,7 @@\n     DELEGATE_TASK_SCHEMA,\n     DelegateEvent,\n     _get_max_concurrent_children,\n+    _load_config,\n     _LEGACY_EVENT_MAP,\n     MAX_DEPTH,\n     check_delegate_requirements,","@@ -2390,6 +2392,71 @@ def test_progress_callback_task_progress_not_misrendered(self):\n class TestConcurrencyDefaults(unittest.TestCase):\n     \"\"\"Tests for the concurrency default and no hard ceiling.\"\"\"\n \n+    def test_load_config_prefers_active_persistent_config_over_cli_defaults(self):\n+        stale_cli = types.ModuleType(\"cli\")\n+        stale_cli.CLI_CONFIG = {\n+            \"delegation\": {\n+                \"max_iterations\": 45,\n+                \"model\": \"\",\n+                \"provider\": \"\",\n+                \"base_url\": \"\",\n+                \"api_key\": \"\",\n+            }\n+        }\n+        active_config = {\n+            \"delegation\": {\n+                \"max_iterations\": 50,\n+                \"max_concurrent_children\": 50,\n+                \"max_spawn_depth\": 10,\n+            }\n+        }\n+\n+        with patch.dict(\"sys.modules\", {\"cli\": stale_cli}):\n+            with patch(\n+                \"hermes_cli.config.load_config_readonly\", return_value=active_config\n+            ):\n+                self.assertEqual(_load_config()[\"max_concurrent_children\"], 50)\n+                self.assertEqual(_get_max_concurrent_children(), 50)\n+\n+    def test_load_config_falls_back_to_cli_config_when_persistent_load_fails(self):\n+        fallback_cli = types.ModuleType(\"cli\")\n+        fallback_cli.CLI_CONFIG = {\n+            \"delegation\": {\n+                \"max_iterations\": 45,\n+                \"max_concurrent_children\": 8,\n+            }\n+        }\n+\n+        with patch.dict(\"sys.modules\", {\"cli\": fallback_cli}):\n+            with patch(\n+                \"hermes_cli.config.load_config_readonly\",\n+                side_effect=RuntimeError(\"boom\"),\n+            ):\n+                self.assertEqual(_load_config()[\"max_concurrent_children\"], 8)\n+\n+    def test_load_config_prefers_cli_config_when_user_config_ignored(self):\n+        # `hermes chat --ignore-user-config` sets HERMES_IGNORE_USER_CONFIG=1,\n+        # which only load_cli_config() honors. The delegation loader must keep\n+        # CLI_CONFIG authoritative under the flag so user config.yaml\n+        # delegation keys stay suppressed.\n+        ignoring_cli = types.ModuleType(\"cli\")\n+        ignoring_cli.CLI_CONFIG = {\n+            \"delegation\": {\n+                \"max_iterations\": 45,\n+                \"max_concurrent_children\": 4,\n+            }\n+        }\n+        user_config = {\"delegation\": {\"max_concurrent_children\": 50}}\n+\n+        with patch.dict(\"sys.modules\", {\"cli\": ignoring_cli}):\n+            with patch.dict(os.environ, {\"HERMES_IGNORE_USER_CONFIG\": \"1\"}):\n+                with patch(\n+                    \"hermes_cli.config.load_config_readonly\",\n+                    return_value=user_config,\n+                ) as mock_loader:\n+                    self.assertEqual(_load_config()[\"max_concurrent_children\"], 4)\n+                    mock_loader.assert_not_called()\n+\n     @patch(\"tools.delegate_tool._load_config\", return_value={})\n     def test_default_is_three(self, mock_cfg):\n         # Clear env var if set"]},{"file":"tools/delegate_tool.py","hunks":["@@ -3098,26 +3098,40 @@ def _resolve_delegation_credentials(cfg: dict, parent_agent) -> dict:\n \n \n def _load_config() -> dict:\n-    \"\"\"Load delegation config from CLI_CONFIG or persistent config.\n-\n-    Checks the runtime config (cli.py CLI_CONFIG) first, then falls back\n-    to the persistent config (hermes_cli/config.py load_config()) so that\n-    ``delegation.model`` / ``delegation.provider`` are picked up regardless\n-    of the entry point (CLI, gateway, cron).\n+    \"\"\"Load delegation config from the active Hermes config.\n+\n+    Prefer the shared persistent loader because it follows the active\n+    HERMES_HOME/profile. ``cli.CLI_CONFIG`` is a legacy fallback for entry\n+    points that cannot import the shared loader; importing it first can return\n+    an old default ``delegation`` block and hide user-set keys such as\n+    ``max_concurrent_children``.\n+\n+    Uses ``load_config_readonly()``: every consumer of this dict is read-only\n+    (``.get()`` lookups), and this runs on each ``get_definitions()`` schema\n+    rebuild via ``_get_max_concurrent_children``, so skipping the defensive\n+    deepcopy matters. Do NOT mutate the returned dict.\n+\n+    ``HERMES_IGNORE_USER_CONFIG=1`` (``hermes chat --ignore-user-config``) is\n+    only honored by the legacy ``cli`` loader, not the shared one, so when the\n+    flag is set we keep ``cli.CLI_CONFIG`` authoritative to preserve the\n+    flag's contract of suppressing user config.yaml settings.\n     \"\"\"\n+    prefer_legacy = os.environ.get(\"HERMES_IGNORE_USER_CONFIG\") == \"1\"\n+    if not prefer_legacy:\n+        try:\n+            from hermes_cli.config import load_config_readonly\n+\n+            full = load_config_readonly()\n+            cfg = full.get(\"delegation\") or {}\n+            if isinstance(cfg, dict):\n+                return cfg\n+        except Exception:\n+            pass\n     try:\n         from cli import CLI_CONFIG\n \n         cfg = CLI_CONFIG.get(\"delegation\") or {}\n-        if cfg:\n-            return cfg\n-    except Exception:\n-        pass\n-    try:\n-        from hermes_cli.config import load_config\n-\n-        full = load_config()\n-        return full.get(\"delegation\") or {}\n+        return cfg if isinstance(cfg, dict) else {}\n     except Exception:\n         return {}\n \n"]}]}],"trust":{"default_tier":"verified","includes_suggested":false}}