merge_config loses nested settings

Done

/home/devdi/devswarm/evals/tasks/deep_merge_config/repo · 2026-11-09 16:13:43 UTC · took 32.7s

  1. Plan (done)
  2. Code (done)
  3. Test (done)
  4. Review (done)
  5. Finish (done)
Cost
$0.0041
Tests
Passed
Iterations
1
Re-plans
0
LLM calls
11
Prompt read from cache
80%

Usage by agent

Cost per agent
planner: $0.0007 planner planner, Cost: $0.0007 $0.0007 coder: $0.0018 coder coder, Cost: $0.0018 $0.0018 tester: $0.0015 tester tester, Cost: $0.0015 $0.0015
Tokens per agent
  • Cache read
  • Cache write
  • Input
  • Output
planner: 7,257 planner planner, Cache read: 5,616 planner, Cache write: 453 planner, Output: 1,180 7,257 coder: 25.3K coder coder, Cache read: 19.1K coder, Cache write: 3,880 coder, Output: 2,320 25.3K tester: 19.6K tester tester, Cache read: 13.1K tester, Cache write: 4,855 tester, Output: 1,614 19.6K
View as table
AgentCostCache readCache writeInputOutput
planner$0.00075,61645381,180
coder$0.001819,1143,880122,320
tester$0.001513,0964,85581,614

Timeline

  1. planner iteration 1 Finished 3 calls · 7,257 tokens · $0.0007 · 9.0s

    Loading…

  2. coder iteration 1 Finished 5 calls · 25.3K tokens · $0.0018 · 12.3s

    Loading…

  3. tester iteration 1 Finished 3 calls · 19.6K tokens · $0.0015 · 10.2s

    Loading…

  4. verify iteration 1 Passed 0.6s
    .......                                                                  [100%]
    7 passed in 0.02s
    

Final diff

diff --git a/settings.py b/settings.py
index 8b119fb..3d3580d 100644
--- a/settings.py
+++ b/settings.py
@@ -1,2 +1,17 @@
+import copy
+
+
 def merge_config(base: dict, override: dict) -> dict:
-    return {**base, **override}
+    """Return a new dict with override merged into base.
+
+    Nested dicts are merged recursively. Any other value in override replaces
+    the value in base. Neither input is modified, and the result does not share
+    mutable state with either input.
+    """
+    result = copy.deepcopy(base)
+    for key, value in override.items():
+        if isinstance(result.get(key), dict) and isinstance(value, dict):
+            result[key] = merge_config(result[key], value)
+        else:
+            result[key] = copy.deepcopy(value)
+    return result
diff --git a/test_settings.py b/test_settings.py
index 52bc84b..4393b20 100644
--- a/test_settings.py
+++ b/test_settings.py
@@ -1,3 +1,5 @@
+import copy
+
 from settings import merge_config
 
 
@@ -7,3 +9,39 @@ def test_flat_merge():
 
 def test_override_wins():
     assert merge_config({"a": 1}, {"a": 2}) == {"a": 2}
+
+
+def test_nested_merge_keeps_base_keys():
+    base = {"db": {"host": "a", "port": 1}}
+    override = {"db": {"port": 2}}
+    assert merge_config(base, override) == {"db": {"host": "a", "port": 2}}
+
+
+def test_non_dict_override_replaces_dict_base():
+    assert merge_config({"db": {"host": "a"}}, {"db": None}) == {"db": None}
+    assert merge_config({"db": {"host": "a"}}, {"db": [1, 2]}) == {"db": [1, 2]}
+
+
+def test_dict_override_replaces_non_dict_base():
+    assert merge_config({"db": 5}, {"db": {"port": 2}}) == {"db": {"port": 2}}
+
+
+def test_keys_only_in_one_side_are_kept():
+    base = {"a": 1, "nested": {"x": 1}}
+    override = {"b": 2, "nested": {"y": 2}}
+    assert merge_config(base, override) == {"a": 1, "b": 2, "nested": {"x": 1, "y": 2}}
+
+
+def test_inputs_are_not_modified():
+    base = {"db": {"host": "a", "port": 1}, "list": [1]}
+    override = {"db": {"port": 2, "opts": {"ssl": True}}}
+    base_copy = copy.deepcopy(base)
+    override_copy = copy.deepcopy(override)
+
+    result = merge_config(base, override)
+
+    assert base == base_copy
+    assert override == override_copy
+    assert result is not base and result is not override
+    result["db"]["opts"]["ssl"] = False
+    assert override == override_copy