Skip to content

59 bug proxy plugin incorrectly parses api parameters into empty strings#60

Merged
touale merged 3 commits intomasterfrom
59-bug-proxy-plugin-incorrectly-parses-api-parameters-into-empty-strings
Feb 8, 2026
Merged

59 bug proxy plugin incorrectly parses api parameters into empty strings#60
touale merged 3 commits intomasterfrom
59-bug-proxy-plugin-incorrectly-parses-api-parameters-into-empty-strings

Conversation

@touale
Copy link
Copy Markdown
Owner

@touale touale commented Feb 8, 2026

Summary by CodeRabbit

  • New Features

    • Added support for generating runtime models from complex schemas (dynamic model creation).
  • Bug Fixes

    • Improved error handling and fallback behavior for proxied async operations, with clearer logging when failures occur.
    • Proxy routing now respects runtime proxy configuration, avoiding unintended proxying when not configured.
  • Tests

    • Expanded test coverage for schema-based model generation and union/optional resolution.

@touale touale linked an issue Feb 8, 2026 that may be closed by this pull request
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 8, 2026

Walkthrough

Adds runtime configuration-aware proxy routing and coroutine validation to the @on_proxy decorator, extends proxy builder schema resolution to support anyOf unions, nulls, and inlined component references via create_pydantic_model, and expands tests to cover the new model-generation and default-resolution behavior.

Changes

Cohort / File(s) Summary
Proxy routing & decorator
src/framex/plugin/on.py
Enforces that @on_proxy targets are async coroutines; checks runtime settings.proxy_functions membership before invoking proxy path; logs fallback errors and delegates to a safe callable when proxying is not configured or fails.
Proxy schema builder
src/framex/plugins/proxy/builder.py
Enhances resolve_annotation to produce Union[...] for anyOf, include NoneType for null, and inline $ref components via create_pydantic_model; resolve_default now returns None when Union includes NoneType.
Tests & API exposure
tests/test_plugins.py
Adds tests that exercise create_pydantic_model with nested components and updates expectations for Optional[int] default resolution; imports create_pydantic_model from builder in tests.

Sequence Diagram(s)

sequenceDiagram
    participant Caller
    participant on_proxy_wrapper
    participant Settings as "settings.proxy_functions"
    participant ProxyService
    participant SafeCallable

    Caller->>on_proxy_wrapper: invoke decorated function (async)
    on_proxy_wrapper->>Settings: check fully-qualified name in proxy_functions?
    alt configured for proxy
        on_proxy_wrapper->>ProxyService: route call via proxy logic
        ProxyService-->>on_proxy_wrapper: result / error
        alt proxy error
            on_proxy_wrapper->>SafeCallable: invoke original implementation
            SafeCallable-->>on_proxy_wrapper: result
        end
    else not configured
        on_proxy_wrapper->>SafeCallable: invoke original implementation
        SafeCallable-->>on_proxy_wrapper: result
    end
    on_proxy_wrapper-->>Caller: return result or raise
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Poem

🐰 I hopped through wrappers, async and bright,

runtime maps guiding each flight.
I stitched unions, nulls, and refs with glee,
then tested the models beneath the tree.
A twitch of whiskers — proxy paths agree!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly addresses the main bug fix: improving the proxy plugin's handling of API parameters, which is reflected in all three modified files (on.py, builder.py, and tests.py).

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 59-bug-proxy-plugin-incorrectly-parses-api-parameters-into-empty-strings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link
Copy Markdown

codecov bot commented Feb 8, 2026

Codecov Report

❌ Patch coverage is 88.88889% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/framex/plugin/on.py 80.00% 1 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/test_plugins.py (1)

256-261: ⚠️ Potential issue | 🟡 Minor

Typo in function name: supply_execptionsupply_exception.

Minor typo — "execption" should be "exception". Since this is only test-internal, it's non-blocking but worth fixing for readability.

🧹 Nitpick comments (3)
tests/test_plugins.py (1)

237-237: Prefer is None over == None.

Using is None is the idiomatic Python comparison for None and avoids potential issues with objects that override __eq__.

Proposed fix
-    assert resolve_default(Optional[int]) == None  # noqa
+    assert resolve_default(Optional[int]) is None
src/framex/plugin/on.py (2)

122-139: Broad except Exception may mask legitimate application errors in the fallback path.

Catching all exceptions means transient proxy-layer issues and permanent application bugs (e.g., TypeError, ValueError from bad input) are handled identically. When the original call fails due to a real bug, the fallback will almost certainly re-raise the same error, but only after emitting a misleading "Falling back" warning.

Consider narrowing the catch to proxy/network-specific exceptions, or at least re-raising exceptions that clearly originate from the user's code rather than the proxy/decorator machinery.

Additionally, the warning on Line 125-128 is logged before the fallback is attempted, so on failure of both paths the log trail is confusing.

♻️ Suggested approach
-            except Exception as e:
+            except (ConnectionError, TimeoutError, RuntimeError) as e:
                 from framex import logger
 
                 logger.warning(
                     f"[Proxy Fallback] Async wrapper for '{full_func_name}' failed with {type(e).__name__}: {e}. "
-                    f"Falling back to the original implementation."
+                    f"Attempting fallback to the original implementation."
                 )

Adjust the exception tuple to match the actual proxy-layer errors you expect. If broad catching is intentional, add a comment explaining why.


148-152: proxy_func_set is rebuilt on every invocation.

set(chain.from_iterable(proxy_settings.proxy_functions.values())) allocates a new set each time the wrapped function is called. If the proxy config is static (or changes infrequently), consider caching it — e.g., building the set once and invalidating on config reload.

If runtime mutability of proxy_functions is a hard requirement, this is fine as-is for correctness, but worth keeping in mind for hot paths.

@touale
Copy link
Copy Markdown
Owner Author

touale commented Feb 8, 2026

@coderabbitai cache "proxy_functions"

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 8, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find and read the proxy config file to understand proxy_functions
fd -t f "config.py" src/framex/plugins/proxy/ --exec cat {}

echo "---separator---"

# Read the on.py file to see how proxy_functions is used
cat src/framex/plugin/on.py

Length of output: 10390


@touale: I've examined the proxy_functions configuration and will cache this information for future reference.

Key findings:

proxy_functions is a configuration field in ProxyPluginConfig (defined in src/framex/plugins/proxy/config.py):

  • Type: dict[str, list[str]] - maps proxy URLs to lists of fully-qualified function names
  • Validation: Each URL key must exist in the proxy_urls configuration
  • Usage: In the @on_proxy decorator, all function name lists are flattened into a set for O(1) membership checking
  • Behavior: Functions not in this set bypass proxy routing and execute locally via safe_callable fallback

✏️ Learnings added
Learnt from: touale
URL: https://github.com/touale/FrameX-kit/pull/60

Timestamp: 2026-02-08T04:40:12.592Z
Learning: In FrameX-kit, `proxy_functions` is a dict[str, list[str]] field in ProxyPluginConfig (src/framex/plugins/proxy/config.py) that maps proxy URLs to lists of fully-qualified function names (format: "module.function_name") to determine which functions should be routed through the proxy.

Learnt from: touale
URL: https://github.com/touale/FrameX-kit/pull/60

Timestamp: 2026-02-08T04:40:12.592Z
Learning: In FrameX-kit's on_proxy decorator (src/framex/plugin/on.py), all function lists from proxy_settings.proxy_functions.values() are flattened using itertools.chain into a single set, and if the decorated function's full name is not in this set, it falls back to local execution via safe_callable instead of proxy routing.

Learnt from: touale
URL: https://github.com/touale/FrameX-kit/pull/60

Timestamp: 2026-02-08T04:40:12.592Z
Learning: In ProxyPluginConfig (src/framex/plugins/proxy/config.py), the proxy_functions configuration has a validator that ensures each URL key in the dictionary exists in the proxy_urls list, raising ValueError if a proxy_functions URL is not covered by proxy_urls.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@touale touale merged commit 2bb6f95 into master Feb 8, 2026
8 of 9 checks passed
@touale touale deleted the 59-bug-proxy-plugin-incorrectly-parses-api-parameters-into-empty-strings branch February 8, 2026 06:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Proxy plugin incorrectly parses API parameters into empty strings

1 participant