Skip to content

Comments

Update haiway with Postgres proxy#417

Merged
KaQuMiQ merged 1 commit intomainfrom
feature/postgres
Sep 17, 2025
Merged

Update haiway with Postgres proxy#417
KaQuMiQ merged 1 commit intomainfrom
feature/postgres

Conversation

@KaQuMiQ
Copy link
Collaborator

@KaQuMiQ KaQuMiQ commented Sep 17, 2025

No description provided.

@coderabbitai
Copy link

coderabbitai bot commented Sep 17, 2025

Walkthrough

  • pyproject.toml: Version bumped 0.84.7 → 0.85.0; haiway dependency updated to ~0.32.0; added optional dependency group postgres -> ["haiway[postgres]", "asyncpg"].
  • src/draive/init.py: Re-exports Immutable from haiway and adds it to all.
  • src/draive/gemini/generating.py: Streaming path now tracks finish_reason/message, accumulates output blocks, logs safety ratings, and raises specific exceptions post-stream based on finish_reason.
  • src/draive/postgres/init.py: New module re-exporting Postgres-related types from haiway.postgres with all.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Add gemini safety custom settings #350 — Alters Gemini streaming completion handling and finish-reason processing, overlapping with the updated streaming logic here.
  • Update dependencies #341 — Re-exports additional haiway symbols and adjusts haiway version, similar to this PR’s init changes and dependency bump.
  • Fix haiway contexts usage #354 — Modifies haiway dependency and public re-exports in src/draive/init.py, aligning with this PR’s API surface updates.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Description Check ❓ Inconclusive No pull request description was provided, so the description cannot be evaluated for relevance; the raw_summary and changes show a haiway version bump, new postgres optional-dependencies, re-exports, and streaming finish-handling changes, but there is no author-provided description to confirm scope or intent. Please add a short PR description summarizing the haiway version bump (~0.31.4 → ~0.32.0), the new postgres optional-dependencies, the draive.postgres re-exports, and the streaming finish-handling changes so reviewers can quickly understand the scope and intent.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title "Update haiway with Postgres proxy" is concise and directly reflects the primary changes in the patch—updating the haiway dependency and adding Postgres-related re-exports/optional-dependencies—so it accurately captures the main intent of the changeset without unnecessary detail.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/postgres

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

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/draive/__init__.py (1)

335-350: Deduplicate repeated names in all.
There are duplicate entries: Resource, ResourceContent, ResourceMissing, ResourceReference, ResourceTemplate, resource. Clean to avoid confusing users and docs.

Apply minimal removals:

-    "Resource",
-    "ResourceContent",
-    "ResourceMissing",
-    "ResourceReference",
-    "ResourceTemplate",
-    "resource",

Also applies to: 399-400

src/draive/gemini/generating.py (1)

326-356: Minor: log safety once per response, not per chunk.
The current loop may emit many safety logs; consider logging only on the first candidate that provides ratings to reduce noise in DEBUG/INFO.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bf7ecbf and 6e0a94e.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (4)
  • pyproject.toml (3 hunks)
  • src/draive/__init__.py (2 hunks)
  • src/draive/gemini/generating.py (4 hunks)
  • src/draive/postgres/__init__.py (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.py

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.py: Use absolute imports from the draive package (e.g., from draive import ...), not relative imports
Follow Ruff import ordering: standard library, third-party, then local imports
Use Python 3.12+ typing features (e.g., | unions, PEP 695 generics)
Prefer abstract/base collection types (Sequence, Mapping, Set, Iterable) over concrete list, dict, set in type hints
Define and raise custom exception types for specific error cases
Use NumPy docstring convention for all functions, classes, and methods
Skip module-level docstrings unless explicitly requested
Docstrings should include Parameters, Returns, Raises, and Notes (if needed) sections

Format all Python code with Ruff formatter (run via make format); do not use any other formatter

Files:

  • src/draive/postgres/__init__.py
  • src/draive/__init__.py
  • src/draive/gemini/generating.py
src/draive/**/*.py

📄 CodeRabbit inference engine (AGENTS.md)

src/draive/**/*.py: Import Haiway symbols directly as from haiway import State, ctx
Use ctx.scope(...) to bind active State instances; avoid global state
Route all logging through ctx.log_* and never use print
Enforce strict typing on public APIs; avoid untyped definitions and Any except at verified third‑party boundaries
Prefer explicit attribute access with static types; avoid dynamic getattr except at narrow boundaries
Use abstract immutable protocols (Mapping, Sequence, Iterable) instead of concrete dict/list/set in public types
Use final where applicable; prefer composition over complex inheritance
Use precise unions (|), narrow with match/isinstance, and avoid cast unless provably safe and localized
Model immutable configuration/data as haiway.State; avoid in‑place mutation and prefer State.updated(...)/functional builders
Access active state via haiway.ctx within async scopes (ctx.scope(...))
Public state methods that dispatch on the active instance must use @statemethod
Add structured, concise logs around generation calls, tool dispatch, and provider requests/responses (without secrets); add metrics via ctx.record where applicable
All I/O is async; keep boundaries async, use ctx.spawn for detached tasks, and avoid custom threading
Translate provider/SDK errors into typed exceptions; never raise bare Exception; preserve context
Compose multimodal content with MultimodalContent.of(...); use ResourceContent/Reference for blobs; wrap custom data in ArtifactContent (use hidden when needed)
Public symbols require NumPy-style docstrings with Parameters/Returns/Raises and rationale when non-obvious
Avoid docstrings for internal helpers; prefer self-explanatory names; skip module-level docstrings
Never log secrets or full request bodies containing keys/tokens
Read credentials from environment variables; resolve via helpers like getenv_str

Files:

  • src/draive/postgres/__init__.py
  • src/draive/__init__.py
  • src/draive/gemini/generating.py
src/draive/__init__.py

📄 CodeRabbit inference engine (AGENTS.md)

Centralize and update all public exports in src/draive/__init__.py when API surface changes

Files:

  • src/draive/__init__.py
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
PR: miquido/draive#0
File: AGENTS.md:0-0
Timestamp: 2025-09-11T15:22:15.967Z
Learning: Applies to src/draive/__init__.py : Centralize and update all public exports in `src/draive/__init__.py` when API surface changes
📚 Learning: 2025-09-11T15:22:15.967Z
Learnt from: CR
PR: miquido/draive#0
File: AGENTS.md:0-0
Timestamp: 2025-09-11T15:22:15.967Z
Learning: Applies to src/draive/__init__.py : Centralize and update all public exports in `src/draive/__init__.py` when API surface changes

Applied to files:

  • src/draive/postgres/__init__.py
  • src/draive/__init__.py
📚 Learning: 2025-09-11T15:22:15.967Z
Learnt from: CR
PR: miquido/draive#0
File: AGENTS.md:0-0
Timestamp: 2025-09-11T15:22:15.967Z
Learning: Applies to src/draive/**/*.py : Import Haiway symbols directly as `from haiway import State, ctx`

Applied to files:

  • src/draive/__init__.py
📚 Learning: 2025-09-08T10:32:32.520Z
Learnt from: CR
PR: miquido/draive#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-08T10:32:32.520Z
Learning: Applies to draive/**/__init__.py : Put exported public symbols into package __init__.py files

Applied to files:

  • src/draive/__init__.py
🧬 Code graph analysis (1)
src/draive/gemini/generating.py (2)
src/draive/gemini/config.py (2)
  • GeminiConfig (25-36)
  • GeminiSafetyConfig (16-22)
src/draive/models/types.py (4)
  • content (458-462)
  • content (597-601)
  • ModelOutputFailed (189-212)
  • ModelOutputLimit (654-682)
🔇 Additional comments (5)
src/draive/__init__.py (2)

28-28: Re-exporting Immutable looks good.
Import from haiway is consistent with our public API pattern.


264-264: Added "Immutable" to all — OK.
Public surface stays aligned with the new import.

src/draive/gemini/generating.py (1)

29-32: Import split for GeminiConfig/SafetyConfig — OK.
Ordering complies with Ruff and local-import rules.

src/draive/postgres/__init__.py (1)

1-17: Straightforward re-exports — looks good.
API is concise and matches the optional dependency group.

pyproject.toml (1)

24-24: No action needed — haiway~=0.32.0 is available on PyPI.
PyPI releases include 0.32.0, so the constraint will resolve as written.

"opentelemetry-exporter-otlp-proto-grpc",
]
httpx = ["haiway[httpx]", "httpx"]
postgres = ["haiway[postgres]", "asyncpg"]
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

🧩 Analysis chain

Optional group “postgres”: confirm duplication and pin asyncpg.
If haiway[postgres] already depends on asyncpg, listing asyncpg here duplicates it. If not, please pin a compatible range (e.g., asyncpg>=0.30,<1) to avoid resolver drift. Latest stable of asyncpg is 0.30.0. (pypi.org)

Option A (if haiway extra includes driver):

-postgres = ["haiway[postgres]", "asyncpg"]
+postgres = ["haiway[postgres]"]

Option B (if not included):

-postgres = ["haiway[postgres]", "asyncpg"]
+postgres = ["haiway[postgres]", "asyncpg>=0.30,<1"]

🌐 Web query:

Does the haiway package define a "postgres" extra that installs asyncpg?

💡 Result:

No — the haiway package does not expose a "postgres" extra that installs asyncpg. (haiway's PyPI project page and repository show no extras for a postgres/asyncpg extra). [1][2]

Sources:
[1] haiway on PyPI. [2] miquido/haiway repository (GitHub).


Pin asyncpg in pyproject.toml — haiway has no postgres extra

haiway does not expose a "postgres" extra that installs asyncpg — pin asyncpg to avoid resolver drift.

-postgres = ["haiway[postgres]", "asyncpg"]
+postgres = ["haiway[postgres]", "asyncpg>=0.30,<1"]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
postgres = ["haiway[postgres]", "asyncpg"]
postgres = ["haiway[postgres]", "asyncpg>=0.30,<1"]
🤖 Prompt for AI Agents
In pyproject.toml at line 50, the dependency list uses "asyncpg" unpinned while
haiway does not provide a "postgres" extra; update that entry to pin asyncpg to
a specific, compatible version range (for example a maintained minor range like
>=0.26.0,<0.28.0) so the resolver won’t drift — edit the postgres line to
replace the bare "asyncpg" with the chosen version specifier and run poetry
lock/resolve to verify.

Comment on lines +367 to +395
if finish_reason == FinishReason.SAFETY:
raise ModelOutputFailed(
provider="gemini",
model=config.model,
reason=f"Safety filtering: {finish_message or ''}",
)

if finish_reason == FinishReason.MAX_TOKENS:
raise ModelOutputLimit(
provider="gemini",
model=config.model,
max_output_tokens=unwrap_missing(
config.max_output_tokens,
default=0,
),
content=tuple(collected_blocks),
)

if finish_reason not in (None, FinishReason.STOP):
raise ModelOutputFailed(
provider="gemini",
model=config.model,
reason=(
f"Completion error: {finish_message}"
if finish_message
else "Completion error"
),
)

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Don’t swallow ModelOutputLimit/ModelOutputFailed raised post-stream.
The broad except Exception will catch the deliberate raises after the stream ends, converting them into ModelOutputFailed and losing semantics. Let our control‑flow exceptions pass through.

Apply a focused guard before the broad catch:

             except ResourceExhausted as exc:
                 ctx.record(
                     ObservabilityLevel.WARNING,
                     event="model.rate_limit",
                     attributes={
                         "model.provider": "gemini",
                         "model.name": config.model,
                     },
                 )
                 # Propagate as ModelRateLimit with randomized backoff window
                 raise ModelRateLimit(
                     provider="gemini",
                     model=config.model,
                     retry_after=random.uniform(*RATE_LIMIT_RETRY_RANGE),  # nosec: B311
                 ) from exc

+            except (ModelOutputFailed, ModelOutputLimit):
+                # Preserve intended control-flow exceptions from end-of-stream checks
+                raise
+
             except Exception as exc:
                 # Convert to ModelOutputFailed for consistency
                 raise ModelOutputFailed(
                     provider="gemini",
                     model=config.model,
                     reason=str(exc),
                 ) from exc

Also applies to: 412-419

🤖 Prompt for AI Agents
In src/draive/gemini/generating.py around lines 367-395 (and similarly 412-419),
the current broad except Exception block swallows deliberate
ModelOutputLimit/ModelOutputFailed exceptions raised after the stream; update
the exception handler so that it re-raises those control-flow exceptions instead
of converting them. Concretely, change the generic except to capture the
exception as e and add an immediate guard like: if isinstance(e,
(ModelOutputLimit, ModelOutputFailed)): raise; otherwise handle/log the
exception as before; ensure the names are in scope or imported as needed.

@KaQuMiQ KaQuMiQ merged commit 05434c0 into main Sep 17, 2025
5 checks passed
@KaQuMiQ KaQuMiQ deleted the feature/postgres branch September 17, 2025 11:34
@coderabbitai coderabbitai bot mentioned this pull request Oct 6, 2025
@coderabbitai coderabbitai bot mentioned this pull request Dec 5, 2025
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.

1 participant