Repository navigation
Conversation
…ypeError Fixes universal-tool-calling-protocol#107. - JSON-encodes object/dictionary and set query parameters so nested content-form query parameters do not raise unhandled TypeError in aiohttp. - Normalizes boolean parameters to 'true'/'false'. - Preserves sequence/list repetition (?tag=a&tag=b) and primitives. - Applied uniformly across HttpCommunicationProtocol, SseCommunicationProtocol, and StreamableHttpCommunicationProtocol. - Adds regression unit test verifying object and list query parameter serialization.
There was a problem hiding this comment.
1 issue found across 4 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="plugins/communication_protocols/http/src/utcp_http/http_communication_protocol.py">
<violation number="1" location="plugins/communication_protocols/http/src/utcp_http/http_communication_protocol.py:503">
P2: Set-valued query arguments still raise `TypeError` because `json.dumps` cannot encode a set. Convert sets to JSON arrays in all three protocol encoders.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
| if isinstance(val, (dict, set)): | ||
| return json.dumps(val, separators=(",", ":")) |
There was a problem hiding this comment.
P2: Set-valued query arguments still raise TypeError because json.dumps cannot encode a set. Convert sets to JSON arrays in all three protocol encoders.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At plugins/communication_protocols/http/src/utcp_http/http_communication_protocol.py, line 503:
<comment>Set-valued query arguments still raise `TypeError` because `json.dumps` cannot encode a set. Convert sets to JSON arrays in all three protocol encoders.</comment>
<file context>
@@ -482,6 +482,30 @@ async def _handle_oauth2(self, auth_details: OAuth2Auth) -> str:
+ return val
+ if isinstance(val, (list, tuple)):
+ return [_encode_val(item) for item in val]
+ if isinstance(val, (dict, set)):
+ return json.dumps(val, separators=(",", ":"))
+ return str(val)
</file context>
| if isinstance(val, (dict, set)): | |
| return json.dumps(val, separators=(",", ":")) | |
| if isinstance(val, dict): | |
| return json.dumps(val, separators=(",", ":")) | |
| if isinstance(val, set): | |
| return json.dumps(list(val), separators=(",", ":")) |
…nested sequences Addresses cubic-dev-ai review feedback on PR universal-tool-calling-protocol#122: - Consolidates _encode_query_params into shared encode_query_params in _security.py. - Converts set values into sorted JSON arrays to avoid TypeError from json.dumps. - JSON-encodes nested sequences/lists so aiohttp does not raise TypeError on matrix/nested arguments. - Adds test cases for set and nested sequence arguments to test_http_communication_protocol.py.
There was a problem hiding this comment.
1 existing issue remains and 1 new issue found across 5 files (changes from recent commits).
Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
View guided diff | Re-trigger cubic
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="plugins/communication_protocols/http/src/utcp_http/_security.py">
<violation number="1" location="plugins/communication_protocols/http/src/utcp_http/_security.py:667">
P2: A `None` argument is encoded as an empty string, so an optional argument passed as null is sent as `key=`. Many servers treat that differently from an absent parameter. Drop `None` values from the query instead, or document the mapping.</violation>
</file>
- Drops query parameters with None values so optional unset arguments are not sent as 'key=' on the wire. - Adds test assertion verifying 'optional_unset' is omitted from the request query.
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
…query arguments - Adds a default handler to json.dumps in encode_query_params: - Nested sets/frozensets serialize to sorted lists. - Other non-JSON types fall back to str(obj). - Updates regression test in test_http_communication_protocol.py with nested sets.
There was a problem hiding this comment.
All reported issues were addressed across 2 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
…query parameters
- Normalizes nested dictionaries so non-string keys (e.g. ints or tuples)
become strings before json.dumps, preventing TypeError since json.dumps
default handler only operates on values.
- Recursively sorts sets into lists and preserves nested structures.
- Adds regression test with numeric dictionary key {100: 'numeric_key'}.
There was a problem hiding this comment.
1 issue found across 2 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="plugins/communication_protocols/http/src/utcp_http/_security.py">
<violation number="1" location="plugins/communication_protocols/http/src/utcp_http/_security.py:670">
P2: This normalization silently overwrites distinct keys such as `100` and `'100'`, dropping one field from the JSON query value. Detect collisions and reject or encode them without loss.</violation>
</file>
Reply with feedback, questions, or to request a fix.
View guided diff | Re-trigger cubic
| """ | ||
| def _normalize(obj: Any) -> Any: | ||
| if isinstance(obj, dict): | ||
| return {str(k): _normalize(v) for k, v in obj.items()} |
There was a problem hiding this comment.
P2: This normalization silently overwrites distinct keys such as 100 and '100', dropping one field from the JSON query value. Detect collisions and reject or encode them without loss.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At plugins/communication_protocols/http/src/utcp_http/_security.py, line 670:
<comment>This normalization silently overwrites distinct keys such as `100` and `'100'`, dropping one field from the JSON query value. Detect collisions and reject or encode them without loss.</comment>
<file context>
@@ -658,17 +658,21 @@ def encode_query_params(params: Dict[str, Any]) -> Dict[str, Any]:
- def _json_default(obj: Any) -> Any:
+ def _normalize(obj: Any) -> Any:
+ if isinstance(obj, dict):
+ return {str(k): _normalize(v) for k, v in obj.items()}
if isinstance(obj, (set, frozenset)):
- return sorted(obj, key=str)
</file context>
| return {str(k): _normalize(v) for k, v in obj.items()} | |
| normalized = {} | |
| for k, v in obj.items(): | |
| key = str(k) | |
| if key in normalized: | |
| raise ValueError(f"Dictionary keys collide after string conversion: {key!r}") | |
| normalized[key] = _normalize(v) | |
| return normalized |
There was a problem hiding this comment.
Fixed in commit 95fbe9a - added collision detection with a ValueError and regression unit test.
…aram normalization - Detects when two distinct dictionary keys map to the same string representation (e.g. 100 and '100') and raises a descriptive ValueError rather than silently overwriting and losing data. - Adds regression unit test verifying collision detection.
Fixes #107.
Problem
When calling
call_toolwith object/dict query arguments (e.g. content-form parameters liketool_args={"filter": {"status": "open"}}),remaining_argswas passed directly into aiohttp'sparams=. Since aiohttp/yarl only accepts primitives or lists for repeated parameters, any object or boolean raised an unhandledTypeErrorbefore sending the HTTP request.Solution
_encode_query_paramshelper acrossHttpCommunicationProtocol,SseCommunicationProtocol, andStreamableHttpCommunicationProtocol:separators=(",", ":")).'true'/'false'.?k=v1&k=v2).plugins/communication_protocols/http/tests/test_http_communication_protocol.pyto verify serialization of objects, lists, booleans, and integers.Testing
pytest plugins/communication_protocols/http/tests/(310 passed, 0 failures).Summary by cubic
Fixes #107. Calling
call_toolwith object or boolean query arguments raised an unhandledTypeErrorbecause aiohttp only accepts primitives or lists for query params. Query values are now serialized with a sharedencode_query_paramshelper before being passed to aiohttp:str().'true'/'false'; lists and tuples are recursively encoded so repeated parameters are preserved (?tag=a&tag=b); primitives pass through unchanged, and None values are dropped.ValueErrorwhen distinct dictionary keys normalize to the same string (e.g.100and'100') instead of silently overwriting.HttpCommunicationProtocol,SseCommunicationProtocol, andStreamableHttpCommunicationProtocol, with regression tests added for objects, sets, nested sequences, booleans, None dropping, non-string keys, and key collisions.Written for commit 95fbe9a. Summary will update on new commits.