From 39f8e117e867aa1fdb3dc3bfb301f74e5f188927 Mon Sep 17 00:00:00 2001 From: 1445043649 <> Date: Mon, 11 May 2026 17:54:57 +0800 Subject: [PATCH] fix(checkpointer): strip SQLAlchemy dialect prefix before passing to LangGraph MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit DeerFlow 用同一个 \`postgres_url\` 喂两条路径: - SQLAlchemy 引擎(需 \`postgresql+asyncpg://\`) - LangGraph AsyncPostgresSaver(psycopg 直连,需 libpq 风格 \`postgresql://\`) PR2 把 .env / config.example.yaml 默认 URL 改成 \`+asyncpg\` 形态后,LangGraph saver from_conn_string 会被 psycopg parser 直接抛 ProgrammingError 'missing "=" after "postgresql+asyncpg://..."'。 修:在 async_provider.py 传给 AsyncPostgresSaver 之前用正则剥掉 \`postgresql+\\w+://\` → \`postgresql://\`。一行修复,让同一个 URL 同时满足 SQLAlchemy 和 LangGraph 两条路径。 实测:make dev-daemon 起 gateway 成功,远程 RDS 上 9 张表(DeerFlow 5 + LangGraph 4)全部 create_all 出来。 Stage 0 PR2 follow-up(不在原 plan task list 内,是 live make dev 触发的)。 Co-Authored-By: Claude Opus 4.7 (1M context) --- .../deerflow/runtime/checkpointer/async_provider.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/backend/packages/harness/deerflow/runtime/checkpointer/async_provider.py b/backend/packages/harness/deerflow/runtime/checkpointer/async_provider.py index 9a04cb1a..8ec66549 100644 --- a/backend/packages/harness/deerflow/runtime/checkpointer/async_provider.py +++ b/backend/packages/harness/deerflow/runtime/checkpointer/async_provider.py @@ -20,6 +20,7 @@ from __future__ import annotations import asyncio import contextlib import logging +import re from collections.abc import AsyncIterator from langgraph.types import Checkpointer @@ -114,7 +115,14 @@ async def _async_checkpointer_from_database(db_config) -> AsyncIterator[Checkpoi if not db_config.postgres_url: raise ValueError("database.postgres_url is required for the postgres backend") - async with AsyncPostgresSaver.from_conn_string(db_config.postgres_url) as saver: + # LangGraph's AsyncPostgresSaver wraps psycopg directly and expects a + # libpq-style conninfo (`postgresql://...`). DeerFlow's own SQLAlchemy + # engine uses the same `postgres_url` but needs the `+asyncpg` dialect + # prefix. Strip the dialect prefix here so the same env var/config + # value satisfies both paths. + lg_conn_str = re.sub(r"^postgresql\+\w+://", "postgresql://", db_config.postgres_url) + + async with AsyncPostgresSaver.from_conn_string(lg_conn_str) as saver: await saver.setup() yield saver return