Skip to content

Conversation

@mogita
Copy link

@mogita mogita commented Dec 16, 2025

Summary by CodeRabbit

  • New Features

    • Added mark delivered functionality for chat channel messages
    • Added call statistics map endpoint for video sessions
  • Improvements

    • Enhanced mark unread functionality with optional message timestamp support
    • Expanded pagination controls for call session participant statistics queries
    • Updated channel update methods with improved data handling

✏️ Tip: You can customize this high-level summary in your review settings.

Copilot AI review requested due to automatic review settings December 16, 2025 05:58
@coderabbitai
Copy link

coderabbitai bot commented Dec 16, 2025

Walkthrough

This PR updates public API signatures across multiple SDK modules: Chat module updates Channel.update to accept ChannelInputRequest, extends mark_unread with message_timestamp parameter, and adds mark_delivered method; Feeds module refines get_or_create parameters and significantly expands rest_client.py with new endpoints and telemetry instrumentation; Moderation and Video modules update type parameters and add new endpoint methods.

Changes

Cohort / File(s) Change Summary
Chat — Method signature updates
getstream/chat/async_channel.py, getstream/chat/channel.py, getstream/chat/async_rest_client.py, getstream/chat/rest_client.py
Updated update() method to accept data: Optional[ChannelInputRequest] instead of ChannelInput; extended mark_unread() with optional message_timestamp: Optional[datetime] parameter forwarded to client calls; added new mark_delivered() method accepting user_id and latest_delivered_messages payload
Feeds — Parameter refinement and endpoint expansion
getstream/feeds/feeds.py, getstream/feeds/rest_client.py
Updated get_or_create() signature to include id_around: Optional[str] and enrichment_options: Optional[EnrichmentOptions], removed activity_selector_options parameter; significantly expanded rest_client.py with numerous new endpoints across collections, feed groups, feed views, bookmarks, comments, follows, and membership operations; added telemetry instrumentation decorator @telemetry.operation_name(...) across all public methods
Moderation — Type parameter conversions
getstream/moderation/async_rest_client.py, getstream/moderation/rest_client.py
Updated method signatures to use ...Payload type variants in place of ...Request types: ModerationPayloadModerationPayloadRequest, FeedsModerationTemplateConfigFeedsModerationTemplateConfigPayload, SortParamSortParamRequest; converted all action payload parameters in submit_action() (ban, block, custom, delete_activity, delete_comment, delete_message, delete_reaction, delete_user, mark_reviewed, shadow_block, unban) to their ...Payload variants
Video — New endpoint and type updates
getstream/video/async_rest_client.py, getstream/video/rest_client.py
Added new get_call_stats_map() method accepting call identifiers and time/exclusion parameters; extended query_call_session_participant_stats() with pagination parameters (limit, prev, next); updated create_call_type() and update_call_type() to accept notification_settings: Optional[NotificationSettingsRequest] instead of NotificationSettings; changed challenge parameter type in resolve_sip_inbound() from SIPChallenge to SIPChallengeRequest

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Areas requiring attention:

  • Feeds rest_client.py: Extensive endpoint additions and telemetry instrumentation across multiple domains (collections, comments, feed groups, feed views, bookmarks, follows, memberships); verify all new endpoints are correctly mapped to their request/response types and telemetry operation names
  • Type parameter conversions across Moderation and Video modules: Ensure ...Payload vs ...Request type switches are consistently applied and do not introduce type safety regressions or serialization issues
  • Chat module signature changes: Verify that ChannelInputRequest is backward compatible or properly documented; confirm mark_unread() with message_timestamp integrates correctly with existing client call patterns

Possibly related PRs

  • [CHA-0] fix unread counts api spec #175: Modifies Channel.update() API in getstream/chat/async_channel.py; this PR also updates the same method signature (changing data parameter type to ChannelInputRequest) and could have overlapping concerns or dependencies.

Suggested reviewers

  • vagruchi

Poem

🐇 Hops of code, a quest so grand,
Types and timestamps, now hand-in-hand,
Feeds and chats and videos grow,
Telemetry beacons aglow, aglow!
Mark delivered, stats do map,
Payloads dance—no type mismatch gap!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.83% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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 accurately describes the main change: code regenerated from refactored OpenAPI specifications, affecting multiple modules across chat, feeds, moderation, and video APIs.
✨ 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 cha-1578_openapi-refactor-codegen

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.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR contains code generated from refactored OpenAPI specifications, updating multiple REST client interfaces and model definitions across the GetStream SDK. The changes primarily involve type renames, new API endpoints, parameter additions, and model restructuring to align with updated API specifications.

Key changes:

  • Added new API methods and endpoints (e.g., get_call_stats_map, collections CRUD operations, mark_delivered)
  • Renamed types for clarity (e.g., NotificationSettingsNotificationSettingsRequest/Response, action request types now use Payload suffix)
  • Added telemetry decorators to feeds client methods
  • Expanded model definitions with new fields and response types

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated no comments.

Show a summary per file
File Description
getstream/video/rest_client.py Added get_call_stats_map method, added pagination params to query_call_session_participant_stats, updated type names for notification settings and SIP challenge
getstream/video/async_rest_client.py Mirror changes to sync client for async version
getstream/moderation/rest_client.py Updated type names for moderation payloads and action requests (added Payload suffix)
getstream/moderation/async_rest_client.py Mirror changes to sync client for async version
getstream/models/__init__.py Extensive model changes: renamed/restructured many dataclasses, added new models for collections, events, notifications; removed deprecated models
getstream/feeds/rest_client.py Added telemetry decorators, new collection endpoints, renamed add_reactionadd_activity_reaction, added new parameters to existing methods
getstream/feeds/feeds.py Updated method signatures to match client changes
getstream/chat/rest_client.py Added mark_delivered method, updated type names, added message_timestamp parameter
getstream/chat/async_rest_client.py Mirror changes to sync client for async version
getstream/chat/channel.py Updated method signatures to match client changes
getstream/chat/async_channel.py Mirror changes to sync client for async version

The changes appear to be auto-generated code with consistent patterns applied across sync and async versions of the clients. No issues were identified in the generated code structure.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@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.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 30dc844 and f9779b3.

📒 Files selected for processing (10)
  • getstream/chat/async_channel.py (3 hunks)
  • getstream/chat/async_rest_client.py (4 hunks)
  • getstream/chat/channel.py (3 hunks)
  • getstream/chat/rest_client.py (4 hunks)
  • getstream/feeds/feeds.py (2 hunks)
  • getstream/feeds/rest_client.py (51 hunks)
  • getstream/moderation/async_rest_client.py (4 hunks)
  • getstream/moderation/rest_client.py (4 hunks)
  • getstream/video/async_rest_client.py (5 hunks)
  • getstream/video/rest_client.py (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

Plugins that work with audio, video, or WebRTC functionality should depend on getstream[webrtc] instead of just getstream to access WebRTC-related dependencies like aiortc, numpy, torch, torchaudio, soundfile, scipy, deepgram-sdk, and elevenlabs

Files:

  • getstream/chat/async_channel.py
  • getstream/chat/async_rest_client.py
  • getstream/moderation/rest_client.py
  • getstream/video/async_rest_client.py
  • getstream/chat/channel.py
  • getstream/moderation/async_rest_client.py
  • getstream/video/rest_client.py
  • getstream/chat/rest_client.py
  • getstream/feeds/rest_client.py
  • getstream/feeds/feeds.py
🧬 Code graph analysis (8)
getstream/chat/async_channel.py (1)
getstream/models/__init__.py (1)
  • ChannelInputRequest (4823-4851)
getstream/chat/async_rest_client.py (5)
getstream/common/telemetry.py (1)
  • operation_name (429-441)
getstream/chat/rest_client.py (1)
  • mark_delivered (145-157)
getstream/models/__init__.py (3)
  • DeliveredMessagePayload (7418-7420)
  • MarkDeliveredResponse (10927-10928)
  • ChannelInputRequest (4823-4851)
getstream/utils/__init__.py (2)
  • build_query_param (94-126)
  • build_body_dict (151-175)
getstream/base.py (2)
  • post (240-256)
  • post (429-445)
getstream/video/async_rest_client.py (3)
getstream/common/telemetry.py (1)
  • operation_name (429-441)
getstream/models/__init__.py (4)
  • QueryCallStatsMapResponse (14474-14538)
  • QueryCallSessionParticipantStatsResponse (14424-14457)
  • NotificationSettingsRequest (12890-12908)
  • SIPChallengeRequest (16585-16627)
getstream/utils/__init__.py (1)
  • build_query_param (94-126)
getstream/chat/channel.py (2)
getstream/stream_response.py (1)
  • data (22-24)
getstream/models/__init__.py (1)
  • ChannelInputRequest (4823-4851)
getstream/moderation/async_rest_client.py (4)
getstream/models/__init__.py (11)
  • ModerationPayloadRequest (12502-12514)
  • BanActionRequestPayload (1901-1919)
  • BlockActionRequestPayload (2040-2043)
  • DeleteActivityRequestPayload (7131-7137)
  • DeleteCommentRequestPayload (7226-7232)
  • DeleteMessageRequestPayload (7291-7297)
  • DeleteReactionRequestPayload (7322-7328)
  • DeleteUserRequestPayload (7369-7384)
  • MarkReviewedRequestPayload (10956-10963)
  • ShadowBlockActionRequestPayload (17303-17306)
  • UnbanActionRequestPayload (18368-18371)
getstream/moderation/rest_client.py (2)
  • ban (35-58)
  • unban (489-508)
getstream/chat/async_rest_client.py (1)
  • delete_message (969-987)
getstream/chat/rest_client.py (1)
  • delete_message (959-977)
getstream/video/rest_client.py (4)
getstream/common/telemetry.py (1)
  • operation_name (429-441)
getstream/video/async_rest_client.py (1)
  • get_call_stats_map (875-903)
getstream/models/__init__.py (4)
  • QueryCallStatsMapResponse (14474-14538)
  • QueryCallSessionParticipantStatsResponse (14424-14457)
  • NotificationSettingsRequest (12890-12908)
  • SIPChallengeRequest (16585-16627)
getstream/utils/__init__.py (1)
  • build_query_param (94-126)
getstream/feeds/rest_client.py (5)
getstream/common/telemetry.py (1)
  • operation_name (429-441)
getstream/base.py (6)
  • post (240-256)
  • post (429-445)
  • delete (276-292)
  • delete (465-481)
  • get (222-238)
  • get (411-427)
getstream/utils/__init__.py (2)
  • build_body_dict (151-175)
  • build_query_param (94-126)
getstream/feeds/feeds.py (1)
  • delete (17-24)
getstream/stream.py (2)
  • feeds (211-212)
  • feeds (316-328)
getstream/feeds/feeds.py (1)
getstream/models/__init__.py (2)
  • FeedInput (8341-8357)
  • EnrichmentOptions (7693-7744)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Upload results
  • GitHub Check: Tests (3.11)
  • GitHub Check: Tests (3.12)
  • GitHub Check: Tests (3.13)
  • GitHub Check: Tests (3.10)
🔇 Additional comments (35)
getstream/video/async_rest_client.py (3)

874-903: LGTM: New get_call_stats_map endpoint added.

The new method follows the established patterns in the codebase with proper telemetry decoration, path parameter handling, and query parameter construction for optional filters.


1028-1028: Breaking change: notification_settings type updated.

The parameter type changed from NotificationSettings to NotificationSettingsRequest. This is a breaking change for callers passing the old type. Ensure migration documentation is provided.


1096-1096: Breaking change: challenge parameter type updated.

The parameter type changed from SIPChallenge to SIPChallengeRequest. Callers using the old type will need to update their code.

getstream/moderation/async_rest_client.py (4)

213-213: Breaking change: moderation_payload type updated to ModerationPayloadRequest.

Callers using the previous ModerationPayload type will need to migrate.


249-249: Breaking change: config parameter type updated.

Type changed from FeedsModerationTemplateConfig to FeedsModerationTemplateConfigPayload.


288-288: Type alignment: sort uses SortParamRequest.

This aligns with other methods in the codebase that already use SortParamRequest for sort parameters.


460-470: Breaking changes: All action payload types updated to *Payload variants.

Multiple parameter types changed:

  • BanActionRequestBanActionRequestPayload
  • BlockActionRequestBlockActionRequestPayload
  • CustomActionRequestCustomActionRequestPayload
  • DeleteActivityRequestDeleteActivityRequestPayload
  • DeleteCommentRequestDeleteCommentRequestPayload
  • DeleteMessageRequestDeleteMessageRequestPayload
  • DeleteReactionRequestDeleteReactionRequestPayload
  • DeleteUserRequestDeleteUserRequestPayload
  • MarkReviewedRequestMarkReviewedRequestPayload
  • ShadowBlockActionRequestShadowBlockActionRequestPayload
  • UnbanActionRequestUnbanActionRequestPayload

Callers will need to update their code to use the new payload types.

getstream/chat/channel.py (2)

71-71: Breaking change: data parameter type updated to ChannelInputRequest.

The parameter type changed from ChannelInput to ChannelInputRequest. Existing callers passing ChannelInput will need to migrate.


329-348: New optional message_timestamp parameter added to mark_unread.

This is an additive, non-breaking change that extends the API to support marking unread by timestamp in addition to message ID.

getstream/chat/async_channel.py (2)

71-71: Breaking change consistent with sync version.

The data parameter type changed to ChannelInputRequest, matching the sync Channel class.


329-348: Async version mirrors sync changes for mark_unread.

The message_timestamp parameter addition is consistent with the sync Channel.mark_unread method.

getstream/feeds/feeds.py (1)

26-66: New optional parameters added to get_or_create.

Two new optional parameters added:

  • id_around: Optional[str] - for around-based pagination
  • enrichment_options: Optional[EnrichmentOptions] - for controlling enrichment behavior

These are additive, non-breaking changes that extend the API surface.

getstream/chat/rest_client.py (3)

144-157: New mark_delivered endpoint added.

This new method allows marking messages as delivered for a user. The implementation follows the established patterns with proper telemetry decoration and parameter handling.


260-260: Breaking change: data parameter type updated in update_channel.

Type changed from ChannelInput to ChannelInputRequest, consistent with the Channel wrapper classes.


627-654: Extended mark_unread with message_timestamp parameter.

The new optional message_timestamp parameter is properly included in the request body via build_body_dict. This is a non-breaking additive change.

getstream/video/rest_client.py (4)

870-899: New get_call_stats_map endpoint looks correct.

The implementation correctly mirrors the async counterpart, using query parameters for optional filters and path parameters for required identifiers. The return type QueryCallStatsMapResponse aligns with the model definition.


1024-1024: Type update to NotificationSettingsRequest is consistent.

The change from NotificationSettings to NotificationSettingsRequest aligns with the new payload variant types for request bodies, matching the async client changes.


1062-1062: Type update in update_call_type matches create_call_type.

Consistent use of NotificationSettingsRequest across both create and update operations.


1090-1090: SIPChallengeRequest type update is appropriate.

The challenge parameter now uses the dedicated request payload type, which is consistent with the API schema refactoring pattern applied throughout this PR.

getstream/chat/async_rest_client.py (4)

146-159: New mark_delivered method implementation is correct.

The async implementation properly mirrors the sync counterpart, using user_id as a query parameter and latest_delivered_messages in the request body. Telemetry decorator is correctly applied.


264-264: Type update to ChannelInputRequest in update_channel is correct.

This aligns with the PR's schema updates for request payload types.


631-658: mark_unread extended with message_timestamp parameter.

The new optional datetime parameter is correctly added to the method signature and included in the request body via build_body_dict. This enhancement allows marking unread by timestamp in addition to message ID.


175-204: Async and sync clients are consistent; type difference between methods appears intentional.

Both the async and sync clients use ChannelInput for get_or_create_distinct_channel and ChannelInputRequest for update_channel. The type difference is not an inconsistency between sync/async implementations but rather reflects intentional schema differences: ChannelInput includes created_by_id, truncated_by_id, and filter_tags fields that ChannelInputRequest omits, and their config_overrides fields reference different types (ChannelConfig vs ConfigOverridesRequest), suggesting the endpoints accept different request structures.

getstream/moderation/rest_client.py (5)

203-225: custom_check correctly updated to use ModerationPayloadRequest.

The type update for moderation_payload parameter aligns with the new payload variant types.


243-252: v2_upsert_template updated with FeedsModerationTemplateConfigPayload.

The config parameter type change is consistent with the schema refactoring.


278-292: query_moderation_flags updated to use SortParamRequest.

Consistent with other methods using the new request type for sort parameters.


448-486: submit_action correctly updated with new payload variant types.

All action parameters (ban, block, custom, delete_*, mark_reviewed, shadow_block, unban) now use their respective ...RequestPayload types, aligning with the schema updates.


254-276: Consider clarifying the intent of type inconsistency in moderation methods.

The flag method (line 263) uses ModerationPayload while custom_check (line 211) uses ModerationPayloadRequest. This pattern is consistent across the async client as well, where check and flag use ModerationPayload, while only custom_check uses ModerationPayloadRequest. Since both types have identical structure, clarify whether this distinction is intentional (e.g., to explicitly mark custom_check as request-only) or if the methods should be unified to use the same type for consistency.

getstream/feeds/rest_client.py (7)

3-3: Telemetry import added for instrumentation.

The addition of telemetry enables observability across all Feeds API methods.


34-80: add_activity extended with new parameters and telemetry.

New optional parameters restrict_replies, skip_enrich_url, and collection_refs expand the API capabilities. Telemetry decorator correctly applied.


505-560: New collection CRUD endpoints added.

The delete_collections, read_collections, update_collections, create_collections, and upsert_collections methods provide comprehensive collection management. Each uses appropriate HTTP methods and parameter handling.


799-808: list_feed_groups extended with include_soft_deleted filter.

Correctly passed as a query parameter for the GET request.


1299-1329: New feed visibility endpoints added.

list_feed_visibilities, get_feed_visibility, and update_feed_visibility provide visibility management capabilities with consistent patterns.


1375-1395: New get_feeds_rate_limits endpoint.

Provides rate limit introspection with platform-specific filters (android, ios, web, server_side).


1604-1617: delete_feed_user_data changed from DELETE to POST.

The method now uses POST with a request body containing hard_delete. This is a semantic change from the typical DELETE pattern but is appropriate when the operation requires request body parameters.

Comment on lines +944 to +956
limit: Optional[int] = None,
prev: Optional[str] = None,
next: Optional[str] = None,
sort: Optional[List[SortParamRequest]] = None,
filter_conditions: Optional[Dict[str, object]] = None,
) -> StreamResponse[QueryCallSessionParticipantStatsResponse]:
query_params = build_query_param(sort=sort, filter_conditions=filter_conditions)
query_params = build_query_param(
limit=limit,
prev=prev,
next=next,
sort=sort,
filter_conditions=filter_conditions,
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for build_query_param function definition
rg -n -B 3 -A 20 "def build_query_param" --type py

Repository: GetStream/stream-py

Length of output: 3411


🏁 Script executed:

#!/bin/bash
# Get the complete build_query_param function
sed -n '94,130p' getstream/utils/__init__.py

Repository: GetStream/stream-py

Length of output: 1485


🏁 Script executed:

#!/bin/bash
# Search for SortParamRequest class definition
rg -n -A 15 "class SortParamRequest" --type py

Repository: GetStream/stream-py

Length of output: 1217


🏁 Script executed:

#!/bin/bash
# Search for DataClassJsonMixin to understand the to_json() method
rg -n "from dataclasses_json\|class DataClassJsonMixin\|def to_json" --type py | head -20

Repository: GetStream/stream-py

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check imports in models file
head -50 getstream/models/__init__.py | grep -E "import|from"

Repository: GetStream/stream-py

Length of output: 419


🏁 Script executed:

#!/bin/bash
# Search for tests or usage of query_call_session_participant_stats
rg -n "query_call_session_participant_stats\|QueryCallSessionParticipantStats" --type py

Repository: GetStream/stream-py

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Search for test files and build_query_param usage
rg -n "build_query_param\|sort.*filter" tests/ --type py | head -30

Repository: GetStream/stream-py

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Find test files and search for sort/filter usage
find . -path ./venv -prune -o -name "*test*.py" -type f -print | head -20

Repository: GetStream/stream-py

Length of output: 729


🏁 Script executed:

#!/bin/bash
# Search for sort and filter_conditions usage in tests
rg -n "sort\|filter_conditions" tests/ --type py | head -30

Repository: GetStream/stream-py

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check the actual method signature in async_rest_client.py around lines 944-956
sed -n '930,970p' getstream/video/async_rest_client.py

Repository: GetStream/stream-py

Length of output: 1545


Fix sort parameter serialization in query parameters.

The sort parameter uses str(v) on SortParamRequest objects instead of calling their to_json() method, resulting in malformed query parameters. Update build_query_param() to check for to_json() before converting list items to strings, or ensure SortParamRequest objects are properly serialized as JSON for the API endpoint.

🤖 Prompt for AI Agents
In getstream/video/async_rest_client.py around lines 944 to 956, the sort
parameter is being converted using str(v) which yields malformed query values
for SortParamRequest objects; update the query param construction to detect
items with a to_json() method (or isinstance check for SortParamRequest) and
call item.to_json() (or json-serialize the dict) when present, otherwise
stringify primitives, ensuring the final sort list is properly JSON-serialized
or encoded for the API query string.

Comment on lines +940 to +952
limit: Optional[int] = None,
prev: Optional[str] = None,
next: Optional[str] = None,
sort: Optional[List[SortParamRequest]] = None,
filter_conditions: Optional[Dict[str, object]] = None,
) -> StreamResponse[QueryCallSessionParticipantStatsResponse]:
query_params = build_query_param(sort=sort, filter_conditions=filter_conditions)
query_params = build_query_param(
limit=limit,
prev=prev,
next=next,
sort=sort,
filter_conditions=filter_conditions,
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if the file exists and examine the specified lines
if [ -f "getstream/video/rest_client.py" ]; then
  echo "=== Lines 935-955 of getstream/video/rest_client.py ==="
  sed -n '935,955p' getstream/video/rest_client.py
else
  echo "File not found"
fi

Repository: GetStream/stream-py

Length of output: 827


🏁 Script executed:

#!/bin/bash
# Search for the build_query_param function
rg -n "def build_query_param" --type py

Repository: GetStream/stream-py

Length of output: 203


🏁 Script executed:

#!/bin/bash
# Check for query_call_session_participant_stats in async client
rg -n -A 20 "def query_call_session_participant_stats" getstream/video/async_rest_client.py

Repository: GetStream/stream-py

Length of output: 861


🏁 Script executed:

#!/bin/bash
# Examine the build_query_param implementation
sed -n '94,130p' getstream/utils/__init__.py

Repository: GetStream/stream-py

Length of output: 1485


🏁 Script executed:

#!/bin/bash
# Search for SortParamRequest definition
rg -n "class SortParamRequest" --type py

Repository: GetStream/stream-py

Length of output: 141


🏁 Script executed:

#!/bin/bash
# Check if SortParamRequest has to_json method
rg -n -A 10 "class SortParamRequest" --type py

Repository: GetStream/stream-py

Length of output: 808


🏁 Script executed:

#!/bin/bash
# Check DataClassJsonMixin to understand how SortParamRequest serializes
rg -n "class DataClassJsonMixin" --type py

Repository: GetStream/stream-py

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Look for how the query parameters are actually used in the request
sed -n '950,970p' getstream/video/rest_client.py

Repository: GetStream/stream-py

Length of output: 731


🏁 Script executed:

#!/bin/bash
# Check the exact import and confirmation that SortParamRequest has to_json
rg -n "to_json" getstream/models/__init__.py | head -20

Repository: GetStream/stream-py

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check if DataClassJsonMixin is imported and used
rg -n "DataClassJsonMixin" getstream/models/__init__.py | head -10

Repository: GetStream/stream-py

Length of output: 499


🏁 Script executed:

#!/bin/bash
# Check the imports at the top of utils/__init__.py to see what quote is used
head -30 getstream/utils/__init__.py

Repository: GetStream/stream-py

Length of output: 741


🏁 Script executed:

#!/bin/bash
# Let's also verify the actual HTTP request handling to see if there's any limit consideration
rg -n "def get\(" getstream/video/rest_client.py | head -5

Repository: GetStream/stream-py

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Find the get method in rest_client to see how query_params are constructed
rg -n "def get" getstream/video/rest_client.py | grep -E "def get\(" | head -3

Repository: GetStream/stream-py

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Look at the actual HTTP request call in the get method
rg -n -A 15 "def get\(self" getstream/video/rest_client.py | head -30

Repository: GetStream/stream-py

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check the base class to understand HTTP request handling
rg -n "class.*RestClient" getstream/video/rest_client.py

Repository: GetStream/stream-py

Length of output: 99


🏁 Script executed:

#!/bin/bash
# Look at how query_params are passed in the self.get call
rg -n "query_params=" getstream/video/rest_client.py | head -10

Repository: GetStream/stream-py

Length of output: 405


🏁 Script executed:

#!/bin/bash
# Find BaseClient implementation
rg -n "class BaseClient" --type py

Repository: GetStream/stream-py

Length of output: 164


🏁 Script executed:

#!/bin/bash
# Look for the get method in BaseClient
rg -n -A 20 "def get\(self" getstream/base_client.py | head -40

Repository: GetStream/stream-py

Length of output: 127


🏁 Script executed:

#!/bin/bash
# Find the get method in BaseClient located at getstream/base.py
rg -n -A 20 "def get\(self" getstream/base.py | head -50

Repository: GetStream/stream-py

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check what happens with query_params in the HTTP request
rg -n "query_params" getstream/base.py | head -20

Repository: GetStream/stream-py

Length of output: 1109


🏁 Script executed:

#!/bin/bash
# Check the _prepare_request method implementation
sed -n '98,115p' getstream/base.py

Repository: GetStream/stream-py

Length of output: 819


🏁 Script executed:

#!/bin/bash
# Check what HTTP library is used (requests import)
head -50 getstream/base.py | grep -E "import|from"

Repository: GetStream/stream-py

Length of output: 629


🏁 Script executed:

#!/bin/bash
# Check if SortParamRequest or DataClassJsonMixin provides to_json method
rg -n "to_json" getstream/ --type py | grep -i "sortparam\|dataclass" | head -20

Repository: GetStream/stream-py

Length of output: 45


🏁 Script executed:

#!/bin/bash
# Check what DataClassJsonMixin provides
python3 -c "from dataclasses_json import DataClassJsonMixin; print(dir(DataClassJsonMixin))" 2>/dev/null || echo "Module check failed, let's verify with rg"
rg -n "\.to_json\(" getstream/ --type py | head -10

Repository: GetStream/stream-py

Length of output: 149


🏁 Script executed:

#!/bin/bash
# Let's check if there's a test file that shows how sort parameter is used
rg -n "query_call_session_participant_stats" getstream/ --type py -A 3 | head -40

Repository: GetStream/stream-py

Length of output: 885


🏁 Script executed:

#!/bin/bash
# Check if there are any tests for build_query_param
rg -n "build_query_param" getstream/ --type py -B 2 -A 5 | head -60

Repository: GetStream/stream-py

Length of output: 3512


🏁 Script executed:

#!/bin/bash
# Let's verify the exact serialization behavior with a simple test
cat > /tmp/test_serialize.py << 'EOF'
import sys
sys.path.insert(0, '/tmp')

# Simulate what build_query_param does with a list
from urllib.parse import quote

class MockSortParam:
    def __init__(self, field, direction):
        self.field = field
        self.direction = direction
    
    def __repr__(self):
        return f"SortParamRequest(field={self.field}, direction={self.direction})"
    
    def to_json(self):
        return f'{{"field":"{self.field}","direction":{self.direction}}}'

# Test what happens with list serialization
sort_list = [MockSortParam("created_at", 1), MockSortParam("updated_at", -1)]

# This is what build_query_param does for lists:
result = ",".join(quote(str(v)) for v in sort_list)
print("List serialization (current approach):")
print(result)
print()

# This is what it should do if checking to_json:
result_better = ",".join(quote(v.to_json()) if hasattr(v, 'to_json') else quote(str(v)) for v in sort_list)
print("List serialization (if checking to_json):")
print(result_better)
EOF
python3 /tmp/test_serialize.py

Repository: GetStream/stream-py

Length of output: 384


🏁 Script executed:

#!/bin/bash
# Let's check if dataclasses_json actually provides to_json method
cat > /tmp/test_dataclass.py << 'EOF'
from dataclasses import dataclass
from dataclasses_json import DataClassJsonMixin

@dataclass
class TestSort(DataClassJsonMixin):
    field: str
    direction: int

obj = TestSort(field="created_at", direction=1)
print("Has to_json:", hasattr(obj, 'to_json'))
print("Callable to_json:", hasattr(obj, 'to_json') and callable(obj.to_json))
if hasattr(obj, 'to_json') and callable(obj.to_json):
    print("to_json() result:", obj.to_json())
print("str() result:", str(obj))
EOF
python3 /tmp/test_dataclass.py

Repository: GetStream/stream-py

Length of output: 258


🏁 Script executed:

#!/bin/bash
# Now let's verify how the query parameters are actually passed to httpx
rg -n "params=query_params" getstream/base.py -B 3 -A 3

Repository: GetStream/stream-py

Length of output: 3367


🏁 Script executed:

#!/bin/bash
# Let's check how httpx handles query parameters
cat > /tmp/test_httpx.py << 'EOF'
import httpx

# Simulate what happens when we pass query_params to httpx
params = {
    "sort": "SortParamRequest%28field%3Dcreated_at%2C%20direction%3D1%29,SortParamRequest%28field%3Dupdated_at%2C%20direction%3D-1%29",
    "filter_conditions": '{"created_at": {"$gte": "2024-01-01"}, "status": "active"}'
}

# Create a sample request
req = httpx.Request("GET", "http://example.com/api/endpoint", params=params)
print("Generated URL:")
print(req.url)
print()
print("URL length:", len(str(req.url)))
EOF
python3 /tmp/test_httpx.py

Repository: GetStream/stream-py

Length of output: 393


🏁 Script executed:

#!/bin/bash
# Check if there are any other similar patterns in the codebase
rg -n "isinstance.*list" getstream/utils/__init__.py -B 2 -A 5

Repository: GetStream/stream-py

Length of output: 1048


Sort parameter serialization bypasses to_json() method for list elements.

The build_query_param function (line 120-122) processes list values using str(v) instead of checking for to_json() methods on elements. When sort is passed as List[SortParamRequest], this produces verbose string representations like SortParamRequest(field=created_at, direction=1) instead of JSON, resulting in double-encoded query parameters (e.g., SortParamRequest%2528field%253Dcreated_at...). While filter_conditions (Dict) correctly uses json.dumps(), the sort parameter should similarly leverage the to_json() method available on DataClassJsonMixin-based objects to produce clean, properly encoded query strings and avoid unnecessarily long URLs.

🤖 Prompt for AI Agents
In getstream/video/rest_client.py around lines 940 to 952, the sort list is
being passed through build_query_param which currently stringifies list elements
with str(v) causing verbose, non-JSON and double-encoded query values; update
the serialization so that when a list element has a to_json() method (or is an
instance of DataClassJsonMixin) you call that to obtain a JSON-serializable
dict/string (or call element.to_json() and then json.loads if it returns a JSON
string), build a list of those serializable representations and json.dumps the
whole list before adding to the query params; alternatively, special-case the
sort parameter before calling build_query_param to map each SortParamRequest to
its JSON form and pass the JSON-dumped list so query strings are compact and
correctly encoded.

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.

2 participants