Skip to content

Commit 66ff79c

Browse files
DavidsonGomesclaude
andcommitted
fix(db,chat): translate sslmode→ssl for asyncpg and rebind chat handler request param
* get_async_db_url now rewrites `sslmode=` to `ssl=` in the async DSN. asyncpg rejects the libpq-style `sslmode` query parameter, which made DatabaseSessionService.get_session_by_id explode with "connect() got an unexpected keyword argument 'sslmode'" whenever the managed Postgres URL required SSL. * POST /api/v1/chat/{agent_id}/{session_id} was naming its Pydantic body `request`, shadowing the FastAPI Request used by error_response(). When the asyncpg crash above fired the generic except, error_response tried to read `request.url.path` on a ChatRequest model and raised AttributeError, hiding the real cause. Renamed the body to `payload` and added an explicit `request: Request` parameter for error responses. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 17438a3 commit 66ff79c

2 files changed

Lines changed: 19 additions & 9 deletions

File tree

src/api/chat_routes.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
APIRouter,
3232
Depends,
3333
HTTPException,
34+
Request,
3435
status,
3536
WebSocket,
3637
WebSocketDisconnect,
@@ -624,9 +625,10 @@ async def websocket_live_chat(
624625
}
625626
)
626627
async def chat(
627-
request: ChatRequest,
628+
payload: ChatRequest,
628629
agent_id: str,
629630
session_id: str,
631+
request: Request,
630632
current_user: dict = Depends(get_current_user),
631633
db: Session = Depends(get_db),
632634
_: None = Depends(RequirePermission("ai_agent_processor", "execute")),
@@ -637,13 +639,13 @@ async def chat(
637639
final_response = await run_agent_adk(
638640
agent_id,
639641
user_id,
640-
request.message,
642+
payload.message,
641643
session_service,
642644
artifacts_service,
643645
memory_service,
644646
db,
645647
session_id=session_id,
646-
files=request.files,
648+
files=payload.files,
647649
)
648650

649651
return success_response(

src/services/service_providers.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,21 +40,29 @@
4040

4141
def get_async_db_url(db_url: str) -> str:
4242
"""Convert PostgreSQL connection string to async format (postgresql+asyncpg://).
43-
43+
44+
asyncpg does not accept the libpq-style ``sslmode`` query parameter — it
45+
uses ``ssl`` instead. We rewrite the URL so a single DSN with
46+
``sslmode=require`` (used by psycopg2 and the rest of the stack) still
47+
works when the async driver picks it up.
48+
4449
Args:
4550
db_url: PostgreSQL connection string (postgresql://...)
46-
51+
4752
Returns:
48-
Async PostgreSQL connection string (postgresql+asyncpg://...)
53+
Async PostgreSQL connection string (postgresql+asyncpg://...) with
54+
any ``sslmode=`` rewritten to ``ssl=``.
4955
"""
5056
if db_url.startswith("postgresql://"):
51-
return db_url.replace("postgresql://", "postgresql+asyncpg://", 1)
57+
result = db_url.replace("postgresql://", "postgresql+asyncpg://", 1)
5258
elif db_url.startswith("postgresql+asyncpg://"):
53-
return db_url
59+
result = db_url
5460
else:
55-
# If already in async format or other format, return as is
5661
return db_url
5762

63+
# asyncpg rejects `sslmode=`; translate it to `ssl=` keeping the value.
64+
return result.replace("?sslmode=", "?ssl=").replace("&sslmode=", "&ssl=")
65+
5866

5967
# Initialize session service based on AI engine
6068
# DatabaseSessionService requires async driver (asyncpg)

0 commit comments

Comments
 (0)