mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-17 00:30:45 +08:00
feat(persistence): PostgreSQL assistant store, chat persist fixes, gateway scripts
- Add SQLAlchemy Core repos, pg adapter/compat, assistant_store factory, Alembic bootstrap and migration/cutover scripts. - Harden chat_message writes (NUL scrub for PG), turn_uuid on attempt failure, WS turn_runner fallbacks and gateway executed_turn_uuid init. - start_gateway: log paths, PS7 stderr handling via cmd, background stdout/stderr redirect; runtime assistant_runtime_log_dir export. - Ops: clear_all_chat_sessions with PG-only --postgresql and env-gated wipe; clear_postgres_chat_sessions.ps1. - Tests: SA repos, pg compat, persist fallback, smoke env isolation; CI and docs touch-ups. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
2b32d11f43
commit
d14e9d3596
103 changed files with 7574 additions and 1641 deletions
68
svc/persistence/pg_adapter.py
Normal file
68
svc/persistence/pg_adapter.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
"""psycopg connection surface compatible with sqlite3 usage in SqliteStore."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, Iterable, Sequence
|
||||
|
||||
import psycopg
|
||||
from psycopg.rows import dict_row
|
||||
|
||||
from svc.persistence.pg_compat import adapt_sql_for_postgres
|
||||
|
||||
|
||||
def normalize_psycopg_conninfo(url: str) -> str:
|
||||
"""Strip SQLAlchemy driver suffix so :func:`psycopg.connect` accepts the URI."""
|
||||
u = str(url or "").strip()
|
||||
for prefix in (
|
||||
"postgresql+psycopg://",
|
||||
"postgresql+psycopg2://",
|
||||
"postgres+psycopg://",
|
||||
"postgres+psycopg2://",
|
||||
):
|
||||
if u.startswith(prefix):
|
||||
rest = u.split("://", 1)[1]
|
||||
return "postgresql://" + rest
|
||||
return u
|
||||
|
||||
|
||||
class PgCursorShim:
|
||||
def __init__(self, raw: Any) -> None:
|
||||
self._raw = raw
|
||||
|
||||
def fetchone(self) -> Any:
|
||||
return self._raw.fetchone()
|
||||
|
||||
def fetchall(self) -> list[Any]:
|
||||
return self._raw.fetchall()
|
||||
|
||||
@property
|
||||
def lastrowid(self) -> int:
|
||||
return 0
|
||||
|
||||
@property
|
||||
def rowcount(self) -> int:
|
||||
return int(self._raw.rowcount or 0)
|
||||
|
||||
def __iter__(self) -> Iterable[Any]:
|
||||
return iter(self._raw)
|
||||
|
||||
|
||||
class PgConnShim:
|
||||
def __init__(self, raw: psycopg.Connection) -> None:
|
||||
self._raw = raw
|
||||
|
||||
def execute(self, sql: str, params: Sequence[Any] | None = None) -> PgCursorShim:
|
||||
adapted = adapt_sql_for_postgres(sql)
|
||||
cur = self._raw.execute(adapted, params or ())
|
||||
return PgCursorShim(cur)
|
||||
|
||||
def executemany(self, sql: str, seq_of_params: Sequence[Sequence[Any]]) -> None:
|
||||
adapted = adapt_sql_for_postgres(sql)
|
||||
self._raw.executemany(adapted, seq_of_params)
|
||||
|
||||
|
||||
def connect_postgres(url: str) -> psycopg.Connection:
|
||||
return psycopg.connect(normalize_psycopg_conninfo(url), row_factory=dict_row)
|
||||
|
||||
|
||||
__all__ = ["PgConnShim", "PgCursorShim", "connect_postgres", "normalize_psycopg_conninfo"]
|
||||
Loading…
Add table
Add a link
Reference in a new issue