Skip to content

chore: release v0.4.0 - #272

Merged
pontino merged 1 commit into
mainfrom
release/v0.4.0
Sep 7, 2026
Merged

pontino merged 1 commit into
mainfrom
release/v0.4.0

Conversation

@eggai-release-bot

Copy link
Copy Markdown
Contributor

Release v0.4.0

Added

Fixed

  • A2A executor: the JSON-serialisation fallback caught the non-existent
    json.JSONEncodeError, so a failing json.dumps raised AttributeError and
    masked the real error. It now catches (TypeError, ValueError).
  • A2A executor: the "unknown skill" error path enqueued a raw dict instead of a
    proper A2A message; a skill registered with data_type=None raised
    TypeError when building the message and now falls back to BaseMessage.
  • Typed subscriptions: a data_type whose type field has no default (e.g. raw
    BaseMessage) silently dropped every message; subscribe() now raises
    ValueError asking for a default discriminator.
  • Agent.subscribe(): plugin-prefixed kwargs (e.g. a2a_*) on an agent whose
    plugin was never initialised raised an opaque KeyError; now ValueError.
  • RedisTransport: agent.stop() could hang forever on Python 3.10/3.11 with
    redis-py >= 8. redis-py 8 sends every command through asyncio.wait_for
    (socket_timeout now defaults to 5s), and on CPython < 3.12 wait_for can
    swallow the CancelledError when the inner await completes concurrently, so
    the reclaimer task survived its own cancellation. The reclaimer loop now exits
    on a running flag as well as on cancellation.
  • RedisTransport retries with a non-default EGGAI_NAMESPACE (RedisTransport: with a non-default EGGAI_NAMESPACE the reclaimer, retry and DLQ streams use eggai.<ns>.<topic> while consumption uses <ns>.<topic>, so retries never fire #261): the
    reclaimer, group monitor, .retry and .dlq streams were keyed under
    eggai.<ns>.<topic> while consumption and publishing used <ns>.<topic>, so
    retry_on_idle_ms / max_retries never fired outside the default namespace.
    The transport no longer adds its own eggai. prefix; Channel already
    namespaces the name exactly once. After upgrading, entries stuck in the PEL
    under a custom namespace are retried immediately and dead-lettered once the
    retry budget is exhausted. Stale empty eggai.<ns>.* shadow keys can be
    deleted.
  • PendingReclaimer: the retry envelope's header length prefix counted
    characters instead of bytes, truncating non-ASCII header values on every
    retry delivery (PendingReclaimer: _BinaryWriter.write_string uses character count for the length prefix, corrupting non-ASCII headers on retry #263).
  • Agent.subscribe() without a channel listened on the literal eggai.channel
    instead of <EGGAI_NAMESPACE>.channel, so under a custom namespace a bare
    Channel().publish() never reached it (Agent.subscribe() with no channel hardcodes "eggai.channel", ignoring EGGAI_NAMESPACE #264).

Changed

  • Type-annotation cleanups across transports, channel, agent and hooks to
    satisfy mypy (no behaviour change). Transport.subscribe()'s second
    parameter is now named handler in the abstract base and all transports.
  • BREAKING: BaseMessage.data is now required. The generic base previously
    declared data: TData = Field(default_factory=dict). Pydantic does not
    validate defaults, so an envelope missing data validated cleanly on any
    typed subclass (BaseMessage[Order]) with data as a plain {} — the
    handler then crashed on first attribute access, and under NACK_ON_ERROR
    that single malformed message wedged the subscription. A missing or malformed
    payload now fails validation, which typed subscriptions
    (wrap_handler_with_filters) already treat as "not ours: skip and ack".
    The concrete Message keeps its {} default, where the annotation really is
    a dict. Migration: construct payload-less envelopes with Message (or pass
    data= explicitly).
  • Allow ruff 0.16 (ruff >=0.14.4,<0.17) and exclude Markdown from ruff, which
    now formats fenced code blocks by default.
  • RedisTransport: last_id other than ">" together with a consumer group
    now raises ValueError. That combination never delivered new entries (Redis
    returns only the consumer's own pending entries for an explicit id) and
    hot-looped XREADGROUP; the earlier note about replaying a backlog with
    last_id="0" was wrong. Use group_start="0" instead.

After merging, the release will be automatically tagged and published to PyPI.

@eggai-release-bot eggai-release-bot Bot added the release Release PR label Sep 7, 2026
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

QualOps Code Quality Analysis

Status: ✅ PASSED - No issues found

Summary

  • Total Issues: 0
  • Critical: 0 🔴
  • High: 0 🟠
  • Medium: 0 🟡
  • Low: 0 🟢
  • Files Analyzed: 0

No issues found in the analyzed code.

📊 Full Report

View detailed report


Powered by QualOps

@pontino
pontino merged commit 63da80a into main Sep 7, 2026
20 of 21 checks passed

This branch was previously deployed

1 inactive deployment
pypi — 926ccaf7 Deployed Sep 7, 2026 by pontino via pypi-publish #75
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

release Release PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant