Populate full connection attributes and payload for HTTP and WebSocket sessions#1602
Conversation
WalkthroughAdds request payload capture and propagation across HTTP and WebSocket handling: a new Changes
Sequence DiagramsequenceDiagram
participant Client
participant FastAPI_Handler as FastAPI Handler
participant SessionManager
participant Context
participant Workflow
Client->>FastAPI_Handler: Send HTTP or WebSocket request with payload
FastAPI_Handler->>FastAPI_Handler: Capture payload into internal attribute
FastAPI_Handler->>SessionManager: Invoke set metadata (HTTP/WebSocket)
activate SessionManager
SessionManager->>SessionManager: await request.json() (HTTP) / read websocket fields
SessionManager->>Context: Store metadata including payload
deactivate SessionManager
FastAPI_Handler->>Context: Propagate captured payload into session context
FastAPI_Handler->>Workflow: Start workflow using populated context
Workflow->>Context: Access payload via RequestAttributes.payload
Context-->>Workflow: Provide payload and metadata
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
No actionable comments were generated in the recent review. 🎉 🧹 Recent nitpick comments
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@packages/nvidia_nat_core/src/nat/front_ends/fastapi/message_handler.py`:
- Line 122: The payload currently includes PII because
self._user_message_payload is set from message.model_dump(exclude={"security"})
but does not exclude the WebSocketUserMessage.user field; update the call in the
constructor where self._user_message_payload is assigned to exclude "user" as
well (e.g., message.model_dump(exclude={"security", "user"})) or explicitly
remove/redact the user entry before assigning to self._user_message_payload so
RequestAttributes.payload no longer contains name/email; if you intend to keep
user, add clear documentation and ensure downstream consumers treat it as
sensitive.
🧹 Nitpick comments (5)
packages/nvidia_nat_core/src/nat/runtime/user_metadata.py (1)
134-137: Docstring style inconsistency with sibling properties.All other properties in this class use a multi-line Google-style docstring with a
Returns:section. Consider matching that style for consistency.Suggested docstring
`@property` def payload(self) -> dict[str, typing.Any] | None: - """Request payload parsed as a dictionary.""" + """ + This property retrieves the parsed payload from the request. + + Returns: + dict[str, typing.Any] | None + """ return self._request.payloadpackages/nvidia_nat_core/src/nat/runtime/session.py (2)
654-657: Prefer named attributes over tuple indexing for consistency.Lines 597-598 use
request.client.hostandrequest.client.portfor HTTP. Here, tuple indexing[0]/[1]is used for WebSocket. Starlette'sAddressnamedtuple supports both, but using.host/.portwould be more readable and consistent.Suggested change
- host = websocket.client[0] if websocket.client else None - port = websocket.client[1] if websocket.client else None + host = websocket.client.host if websocket.client else None + port = websocket.client.port if websocket.client else None
600-603: Silent fallback on payload parsing is appropriate but consider logging.The broad
except Exception(flagged by ruff BLE001) is reasonable here sincerequest.json()can fail for many valid reasons (empty body, non-JSON content type, already-consumed stream). However, a debug-level log would aid troubleshooting without being noisy.Optional: add debug logging
try: self._context.metadata._request.payload = await request.json() - except Exception: + except Exception: # noqa: BLE001 + logger.debug("Could not parse request body as JSON payload") self._context.metadata._request.payload = Nonepackages/nvidia_nat_core/src/nat/front_ends/fastapi/message_handler.py (1)
410-410: Deeply nested private attribute access bypasses the public API.Accessing
self._session_manager._context.metadata._request.payloadreaches through three layers of private attributes. The same pattern exists inset_metadata_from_websocket, but consider adding a setter method onSessionManager(or the metadata object) to encapsulate this, especially since this is now called from an external class.packages/nvidia_nat_core/tests/nat/server/test_unified_api_server.py (1)
528-575: Redundant import ofMagicMockon Line 530.
MagicMockis already imported at line 22. The local re-import on Line 530 is unnecessary.Remove redundant import
def test_metadata_from_websocket_populates_all_request_attributes() -> None: """Unit test: set_metadata_from_websocket populates context metadata from a mock websocket.""" - from unittest.mock import MagicMock - from nat.builder.context import ContextState from nat.runtime.session import SessionManager
…tions Signed-off-by: Eric Evans <194135482+ericevans-nv@users.noreply.github.com>
a5f380f to
35fbb4e
Compare
…eat/websocket-metadata-extraction
|
/merge |
Description
Closes Issue #1578
Populate all connection attributes (URL, scheme, port, headers, query params, path params, cookies, client info) in
set_metadata_from_websocketto achieve parity with HTTP metadata extraction. Add apayloadfield toRequestAttributesthat stores the parsed HTTP request body and the full WebSocket user message dict (excluding thesecurityfield). Makeset_metadata_from_http_requestasync to supportawait request.json().Changes:
api_server.py— Addpayload: dict[str, Any] | Nonefield to theRequestmodel.user_metadata.py— Addpayloadproperty toRequestAttributes.session.py— Populate all WebSocket connection attributes (url, scheme, headers, query params, path params, client host/port) inset_metadata_from_websocket. Makeset_metadata_from_http_requestasync and read the parsed JSON body intopayload.message_handler.py— Storemessage.model_dump(exclude={"security"})as the WebSocket payload and set it on the session metadata in_run_workflow.test_user_attributes_from_http_requestwith comprehensivetest_metadata_from_http_request_populates_all_request_attributes(integration) andtest_metadata_from_websocket_populates_all_request_attributes(unit) tests that assert every request attribute field for both transport types. Updatetest_session_traceparent.pytoawaitthe now-asyncset_metadata_from_http_request. Addpayloadassertion totest_request_attributes_defaults.By Submitting this PR I confirm:
Summary by CodeRabbit
New Features
Chores
Tests