Skip to content

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 03 Jun 13:27
· 34 commits to main since this release
2cc5c0a

What's Changed

Security

  • Bump dev dependency pytest to ^9.0.0 (9.0.3), with pytest-asyncio to >=1.0,<2 (1.4.0) for compatibility, to remediate GHSA-6w46-j5rx-g56g (insecure tmpdir handling). Test-only; no runtime impact.

Changed

  • Bump fastmcp from ^2.14.0 to ^3.0.0 (resolves to 3.4.0), which pulls in authlib 1.7.2. The MCP adapter now uses Tool.to_mcp_tool() to read tool schemas, since fastmcp 3.x list_tools() returns FunctionTool objects that expose schemas via parameters/output_schema instead of inputSchema/outputSchema.

Added

  • Distributed tracing via OpenTelemetry: Agents now propagate a shared trace_id across every message hop. Opt-in via setup_tracing(); zero-cost when not configured.

Fixed

  • RedisTransport (#225): Retry and DLQ stream keys are now per-handler
    ({channel}.{handler_suffix}.retry / .dlq) instead of per-channel.
    Previously, multiple handlers subscribing to the same channel with different
    consumer groups shared a single {channel}.retry stream, so one handler's
    reclaimed failure would be redelivered to every handler on that channel
    via its auto-created -retry group. This caused work amplification (N
    replays per nack, where N is the number of consumer groups on the channel)
    and visible duplicate side-effects in downstream systems with non-idempotent
    handlers.
  • RedisTransport: A permanently-unparseable ("poison") retry message is now
    routed to the DLQ — or dropped with an error log when no DLQ is configured —
    instead of being re-queued to the retry stream forever. Its retry count can
    never be incremented, so it would previously livelock the per-handler retry
    stream.
  • RedisTransport: The auto-created retry-stream subscriber now always reads
    only new entries (last_id=">") regardless of the main subscription's
    last_id. Restarting with last_id="0" to replay the main backlog no longer
    also replays the retry stream's history on every restart.
  • RedisTransport: A RedisTransport shared across multiple Agents no
    longer spawns duplicate consumer loops or orphans its consumer-group monitor
    task when each agent calls connect(). Re-entrant connect() now starts only
    not-yet-running subscribers and reuses the existing monitor.
  • Tracing: Retry-stream consumption now emits spans with the retry stream as
    messaging.destination instead of the original channel, so retry attempts can
    be observed separately from main-stream processing.
  • RedisTransport: subscribe() now rolls back the in-memory reclaimer configs
    and stream-subscription entries it registered if retry-stream setup fails, so a
    retried start() no longer accumulates orphaned registrations. Identical
    stream-group subscriptions are also de-duplicated.

Changed

  • RedisTransport: retry_on_idle_ms now rejects ack_policy=AckPolicy.ACK
    and AckPolicy.ACK_FIRST with a ValueError. Those acknowledge messages even
    when the handler fails, emptying the PEL the reclaimer scans, which would
    silently disable retries and the DLQ. Use the default NACK_ON_ERROR.

Migration

  • Breaking on-wire change. Existing inflight messages in {channel}.retry
    and {channel}.dlq streams will not be picked up by upgraded consumers —
    they will continue to exist but new retries will land in the per-handler
    streams. Drain the legacy streams before deploying, or XADD any pending
    entries into the new per-handler keys.

Installation

pip install eggai==0.3.0