Repository: marimo-team/marimo

Issue:
mo.cache fails with keyword args
### Describe the bug

`mo.cache` seems to break when keyword args are passed in.

from https://discord.com/channels/1059888774789730424/1353657704211550208

### Environment

<details>

```
0.11.26
```

</details>


### Code to reproduce

```python
import marimo

__generated_with = "0.11.25"
app = marimo.App(width="medium")


@app.cell
def _():
    import marimo as mo
    return (mo,)


@app.cell
def _(function_breaking_mo_cache):
    global_var = function_breaking_mo_cache(param="new_value")
    return (global_var,)


@app.cell
def _(mo):
    @mo.cache
    def function_breaking_mo_cache(param="default"):
        return param
    return (function_breaking_mo_cache,)


if __name__ == "__main__":
    app.run()
```

Discussion:

Solution patch:
diff --git a/marimo/_save/save.py b/marimo/_save/save.py
index eb856a48..0536cf97 100644
--- a/marimo/_save/save.py
+++ b/marimo/_save/save.py
@@ -190,9 +190,14 @@ class _cache_call:
 
         # Rewrite scoped args to prevent shadowed variables
         arg_dict = {f"{ARG_PREFIX}{k}": v for (k, v) in zip(self._args, args)}
-        kwargs = {f"{ARG_PREFIX}{k}": v for (k, v) in kwargs.items()}
+        kwargs_copy = {f"{ARG_PREFIX}{k}": v for (k, v) in kwargs.items()}
         # Capture the call case
-        scope = {**self.scope, **get_context().globals, **arg_dict, **kwargs}
+        scope = {
+            **self.scope,
+            **get_context().globals,
+            **arg_dict,
+            **kwargs_copy,
+        }
         assert self._loader is not None, UNEXPECTED_FAILURE_BOILERPLATE
         attempt = content_cache_attempt_from_base(
             self.base_block,


Test patch:
diff --git a/tests/_save/test_cache.py b/tests/_save/test_cache.py
index 9d81e994..8d7ea77f 100644
--- a/tests/_save/test_cache.py
+++ b/tests/_save/test_cache.py
@@ -1274,6 +1274,36 @@ class TestCacheDecorator:
             assert a != g("world")
             return
 
+    @staticmethod
+    def test_shadowed_kwargs(app) -> None:
+        @app.cell
+        def __():
+            import marimo as mo
+
+            return (mo,)
+
+        @app.cell
+        def __(mo):
+            @mo.cache
+            def g(value="hello"):
+                return value
+
+            return g
+
+        @app.cell
+        def __(g):
+            assert g() == "hello"
+            assert g(value="world") == "world"
+            assert g(123) == 123
+            assert g.hits == 0
+            assert g(value="hello") == "hello"
+            # Subjective whether this hits
+            # But add to test to capture behavior.
+            assert g.hits == 0
+            assert g() == "hello"
+            assert g.hits == 1
+            return
+
     @staticmethod
     def test_shadowed_state(app) -> None:
         @app.cell