-
Notifications
You must be signed in to change notification settings - Fork 12
Update haiway with Postgres proxy #417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,7 +26,10 @@ | |
| from haiway import META_EMPTY, MISSING, ObservabilityLevel, as_dict, as_list, ctx | ||
|
|
||
| from draive.gemini.api import GeminiAPI | ||
| from draive.gemini.config import GeminiConfig, GeminiSafetyConfig | ||
| from draive.gemini.config import ( | ||
| GeminiConfig, | ||
| GeminiSafetyConfig, | ||
| ) | ||
| from draive.gemini.utils import unwrap_missing | ||
| from draive.models import ( | ||
| GenerativeModel, | ||
|
|
@@ -268,7 +271,7 @@ async def _completion( | |
| }, | ||
| ) | ||
|
|
||
| async def _completion_stream( | ||
| async def _completion_stream( # noqa: C901 | ||
| self, | ||
| *, | ||
| instructions: ModelInstructions, | ||
|
|
@@ -320,6 +323,10 @@ async def _completion_stream( | |
| contents=request_content, | ||
| ) | ||
|
|
||
| collected_blocks: list[ModelOutputBlock] = [] | ||
| finish_reason: FinishReason | None = None | ||
| finish_message: str | None = None | ||
|
|
||
| async for chunk in response_stream: | ||
| _record_usage_metrics( | ||
| chunk.usage_metadata, | ||
|
|
@@ -330,14 +337,62 @@ async def _completion_stream( | |
| continue | ||
|
|
||
| chunk_candidate: Candidate = chunk.candidates[0] # we always request only one | ||
| finish_reason = chunk_candidate.finish_reason | ||
| finish_message = chunk_candidate.finish_message | ||
|
|
||
| if chunk_candidate.safety_ratings: | ||
| ctx.record( | ||
| ObservabilityLevel.INFO, | ||
| event="model.safety.results", | ||
| attributes={ | ||
| "results": [ | ||
| f"{rating.category} |blocked: {rating.blocked}" | ||
| f" |probability:{rating.probability_score}" | ||
| f" |severity:{rating.severity_score}" | ||
| for rating in chunk_candidate.safety_ratings | ||
| if rating.category | ||
| ], | ||
| }, | ||
| ) | ||
|
|
||
| if not chunk_candidate.content or not chunk_candidate.content.parts: | ||
| continue | ||
|
|
||
| for part in chunk_candidate.content.parts: | ||
| collected_blocks.extend(_part_as_output_blocks(part)) | ||
| for element in _part_as_stream_elements(part): | ||
| # element is either a MultimodalContentElement or ModelToolRequest | ||
| yield element | ||
|
|
||
| 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" | ||
| ), | ||
| ) | ||
|
|
||
|
Comment on lines
+367
to
+395
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don’t swallow ModelOutputLimit/ModelOutputFailed raised post-stream. 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 excAlso applies to: 412-419 🤖 Prompt for AI Agents |
||
| except ResourceExhausted as exc: | ||
| ctx.record( | ||
| ObservabilityLevel.WARNING, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| from haiway.postgres import ( | ||
| Postgres, | ||
| PostgresConnection, | ||
| PostgresConnectionPool, | ||
| PostgresException, | ||
| PostgresRow, | ||
| PostgresValue, | ||
| ) | ||
|
|
||
| __all__ = ( | ||
| "Postgres", | ||
| "PostgresConnection", | ||
| "PostgresConnectionPool", | ||
| "PostgresException", | ||
| "PostgresRow", | ||
| "PostgresValue", | ||
| ) |
There was a problem hiding this comment.
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 onasyncpg, listingasyncpghere 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):
Option B (if not included):
🌐 Web query:
💡 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.
📝 Committable suggestion
🤖 Prompt for AI Agents